Files
plugin-helper/.agents/skills/beatsaber-plugin-builder/SKILL.md
T

5.9 KiB

name, description
name description
beatsaber-plugin-builder Build, test-compile, or package Beat Saber PC BSIPA plugin source on Linux from local checkouts, GitHub branches, or pull requests. Use when asked to build a Beat Saber plugin, compile a plugin PR, produce a DLL/zip artifact, configure BeatSaberDir/local refs for dotnet builds, or diagnose Linux build failures for .NET Framework BSIPA projects.

Beat Saber Plugin Builder

Use this skill to compile PC BSIPA plugin projects on this Linux host, especially from the plugin-helper repo. The workflow is adapted from the Setlist repo's Linux/Cursor build notes.

For detailed Linux/BSMT behavior, read linux-bsipa-build.md when you need to configure a project, fix missing references, package artifacts, or explain a failure.

Core Workflow

  1. Confirm context.

    pwd
    git status --short
    sed -n '1,220p' plugin-helper.local.toml
    

    In plugin-helper, run commands from repo root. Treat plugin-helper.local.toml as the source of truth for profile instances_root and state_dir values, and keep temporary source checkouts under the chosen profile's state_dir such as <state_dir>/build/<name>. Do not disturb unrelated dirty files.

  2. Resolve source.

    For a GitHub PR, clone or reuse a checkout under the selected profile's <state_dir>/build, add/fetch the upstream remote if needed, and check out the PR head:

    git clone https://github.com/<owner>/<repo>.git <state_dir>/build/<name>
    git -C <state_dir>/build/<name> fetch origin pull/<pr>/head:pr-<pr>
    git -C <state_dir>/build/<name> checkout pr-<pr>
    

    If the PR is from a fork and the repo already has a fork remote, preserve it. Never overwrite local source changes without explicit approval.

  3. Inspect build shape.

    find <checkout> -maxdepth 3 -name '*.sln' -o -name '*.csproj' -o -name 'manifest.json' -o -name 'Directory.Build.props'
    sed -n '1,240p' <project>.csproj
    

    Note target framework, BeatSaberDir, LocalRefsDir, package references, and whether DisableCopyToPlugins is already set.

  4. Choose Beat Saber references.

    Prefer a BSManager instance matching the plugin or manifest gameVersion. Read plugin-helper.local.toml and select the intended profile, then use that profile's instances_root and matching state_dir instead of searching default BSManager paths manually:

    PYTHONPATH=src .venv/bin/python -m plugin_helper --profile <profile-id> instances
    

    Use a local .csproj.user or MSBuild properties rather than committing machine paths. For test builds, pass -p:DisableCopyToPlugins=True and, for BSMT projects that expose it, -p:DisableCopyToGame=True so compilation does not mutate the game install.

  5. Restore and build.

    Prefer the solution when present; otherwise build the plugin .csproj:

    dotnet restore <solution-or-project>
    dotnet build <solution-or-project> -c Release -p:DisableCopyToPlugins=True -p:DisableCopyToGame=True
    

    If the project lacks .NET Framework reference assemblies on Linux, add or pass the package matching the project's target framework, usually Microsoft.NETFramework.ReferenceAssemblies.net48 for current BSIPA projects, as described in the reference file.

  6. Verify Beat Saber API changes before patching gameplay code.

    When a Beat Saber upgrade breaks a type/member reference, first determine whether the API moved assemblies before substituting another type. Inspect the target game DLLs and nearby mod sources:

    strings "<BeatSaberDir>/Beat Saber_Data/Managed/Main.dll" | rg 'TypeOrMemberName'
    strings "<BeatSaberDir>/Beat Saber_Data/Managed/HMLib.dll" | rg 'TypeOrMemberName'
    ilspycmd -t TypeName "<BeatSaberDir>/Beat Saber_Data/Managed/Main.dll" | sed -n '1,220p'
    rg -n 'TypeOrMemberName|NearbyConcept' ~/src/<owner>/<repo> ~/src/Auros/SiraUtil ~/src/nike4613/BeatSaber-IPA-Reloaded
    
  7. Collect artifacts.

    Find produced DLLs and release zips:

    find <checkout> -path '*/bin/*' \( -name '*.dll' -o -name '*.zip' \) -print
    

    Verify the DLL name, version, and manifest. If the result is meant for plugin-helper, place a copy under <state_dir>/instances/<instance>/downloads/<plugin-id>/ for the selected profile and use the helper plan/apply workflow rather than hand-copying into a BSManager instance.

  8. Validate.

    For skill edits inside this repo, run:

    python /home/pleb/.codex/skills/.system/skill-creator/scripts/quick_validate.py .agents/skills/beatsaber-plugin-builder
    PYTHONPATH=src .venv/bin/python -m compileall -q src tests
    PYTHONPATH=src .venv/bin/python -m unittest discover -s tests
    

    For a plugin build, at minimum report the exact dotnet build result and artifact paths. For live game validation, use docs/SMOKETEST.md and tear down Beat Saber processes afterward.

Failure Triage

  • Missing Microsoft.NETFramework.ReferenceAssemblies: add the package matching the target framework, usually Microsoft.NETFramework.ReferenceAssemblies.net48 for current projects, or pass an equivalent MSBuild/package restore fix.
  • Missing Main.dll, HMUI.dll, IPA.Loader.dll, BSML.dll, SongCore.dll, or similar: BeatSaberDir points at the wrong/unmodded instance, or dependencies are absent from Plugins//Libs/.
  • BSMT copies to IPA/Pending or Plugins during build: rebuild with -p:DisableCopyToPlugins=True -p:DisableCopyToGame=True unless the user explicitly wants deployment.
  • NuGet package restore fails because a source is missing: inspect NuGet.config and installed package sources; use repo-local configuration where possible.
  • API compile errors from a PR: inspect the target game/dependency versions before changing code. Prefer one target version rather than compatibility branches unless the user asks for multi-version support.