Refactor agent skills

This commit is contained in:
pleb
2026-07-10 08:42:55 -07:00
parent f4fedaeb34
commit 26def9609d
8 changed files with 291 additions and 102 deletions
@@ -7,6 +7,13 @@ description: Build, test-compile, or package Beat Saber PC BSIPA plugin source o
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. 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.
Before building, read the shared policy references:
- [repo-workflow.md](../references/repo-workflow.md) for repo root, `.venv`, `PYTHONPATH=src`, dirty worktree handling, and validation commands.
- [state-and-profiles.md](../references/state-and-profiles.md) for `.state`, profiles, install identity, instance selection, and checkout locations.
- [artifact-policy.md](../references/artifact-policy.md) when handing a built artifact to `plugin-helper`.
- [live-validation.md](../references/live-validation.md) when validating a built plugin in-game.
For detailed Linux/BSMT behavior, read [linux-bsipa-build.md](references/linux-bsipa-build.md) when you need to configure a project, fix missing references, package artifacts, or explain a failure. For detailed Linux/BSMT behavior, read [linux-bsipa-build.md](references/linux-bsipa-build.md) when you need to configure a project, fix missing references, package artifacts, or explain a failure.
## Core Workflow ## Core Workflow
@@ -19,17 +26,14 @@ For detailed Linux/BSMT behavior, read [linux-bsipa-build.md](references/linux-b
sed -n '1,220p' plugin-helper.local.toml sed -n '1,220p' plugin-helper.local.toml
``` ```
In `plugin-helper`, run commands from repo root. Treat In `plugin-helper`, run commands from repo root. Treat shared profile and
`plugin-helper.local.toml` as the source of truth for profile dirty-worktree policy as binding.
`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. 2. Resolve source.
For a GitHub PR, clone or reuse a checkout under the selected profile's For a GitHub PR, clone or reuse a checkout according to the shared source
`<state_dir>/build`, add/fetch the upstream remote if needed, and check out checkout policy, add/fetch the upstream remote if needed, and check out the
the PR head: PR head:
```bash ```bash
git clone https://github.com/<owner>/<repo>.git <state_dir>/build/<name> git clone https://github.com/<owner>/<repo>.git <state_dir>/build/<name>
@@ -37,7 +41,8 @@ For detailed Linux/BSMT behavior, read [linux-bsipa-build.md](references/linux-b
git -C <state_dir>/build/<name> checkout 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. 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. 3. Inspect build shape.
@@ -51,9 +56,11 @@ For detailed Linux/BSMT behavior, read [linux-bsipa-build.md](references/linux-b
4. Choose Beat Saber references. 4. Choose Beat Saber references.
Prefer a BSManager instance matching the plugin or manifest `gameVersion`. Prefer a BSManager instance matching the plugin or manifest `gameVersion`.
Read `plugin-helper.local.toml` and select the intended profile, then use If the user did not specify an instance and the plugin does not require a
that profile's `instances_root` and matching `state_dir` instead of narrower version, use the latest available BSInstance. Read
searching default BSManager paths manually: `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:
```bash ```bash
PYTHONPATH=src .venv/bin/python -m plugin_helper --profile <profile-id> instances PYTHONPATH=src .venv/bin/python -m plugin_helper --profile <profile-id> instances
@@ -107,7 +114,7 @@ For detailed Linux/BSMT behavior, read [linux-bsipa-build.md](references/linux-b
8. Validate. 8. Validate.
For skill edits inside this repo, run: For skill edits inside this repo, run the shared skill validation plus:
```bash ```bash
python /home/pleb/.codex/skills/.system/skill-creator/scripts/quick_validate.py .agents/skills/beatsaber-plugin-builder python /home/pleb/.codex/skills/.system/skill-creator/scripts/quick_validate.py .agents/skills/beatsaber-plugin-builder
@@ -43,7 +43,7 @@ Prefer machine-local configuration in `<Project>.csproj.user`:
```xml ```xml
<Project> <Project>
<PropertyGroup> <PropertyGroup>
<BeatSaberDir>/path/from/selected/profile/instances_root/1.44.1</BeatSaberDir> <BeatSaberDir>/path/from/selected/profile/instances_root/selected-instance</BeatSaberDir>
</PropertyGroup> </PropertyGroup>
</Project> </Project>
``` ```
@@ -7,32 +7,12 @@ description: Install or update a Beat Saber plugin in the plugin-helper repo by
Use the repository's own `plugin-helper` commands to manage plugins for BSManager instances whenever the helper supports the operation. Use the repository's own `plugin-helper` commands to manage plugins for BSManager instances whenever the helper supports the operation.
## Hard Guardrail Before acting, read the shared policy references:
For ordinary GitHub-hosted plugins, require an explicit GitHub repository or - [repo-workflow.md](../references/repo-workflow.md) for repo root, `.venv`, `PYTHONPATH=src`, dirty worktree handling, and validation commands.
release URL from the user's prompt or from a user-provided local planning note - [state-and-profiles.md](../references/state-and-profiles.md) for `.state`, profiles, install identity, instance selection, and checkout locations.
before selecting any release. - [artifact-policy.md](../references/artifact-policy.md) for GitHub/BeatMods/private-source/checksum/bootstrap policy.
- [live-validation.md](../references/live-validation.md) for smoke tests, logs, and process cleanup.
- If the user has provided a GitHub repository URL but not a release URL, use
that exact repository's release API and choose the most appropriate
non-draft, non-prerelease release/asset for the target Beat Saber instance.
- If the user has provided no GitHub repository or release URL for the plugin,
stop and ask the user for one.
- Do not search the web to discover a repository or "correct" project URL.
- Do not substitute a similar repo, fork, project, or package name.
- If the provided URL is a general releases page, use that repo's release API and choose the latest non-draft, non-prerelease release unless the user asks for a specific tag/version.
- If the provided URL is a tag URL, use that exact tag.
Exception: if the user explicitly asks to bootstrap a Beat Saber version or
install verified mods without providing GitHub URLs, use BeatMods metadata to
identify compatible versions and dependency closure. Still prefer upstream
GitHub release artifacts when BeatMods exposes a `gitUrl` and a matching
release/asset can be found. Use BeatMods CDN artifacts only when the upstream
artifact is inaccessible, no matching upstream release asset exists, the package
is effectively BeatMods-only, or the package is a framework/library dependency
such as .NET assemblies. Record the artifact source plus BeatMods `modVersion`,
version id, `zipHash`, dependencies, and supported game version in the repo
notes/lock data.
## Workflow ## Workflow
@@ -58,10 +38,12 @@ notes/lock data.
3. Determine the instance. 3. Determine the instance.
Prefer the instance the user names. If omitted and the working context clearly points at one lockfile, use that instance. Otherwise run: Prefer the instance the user names. If omitted, use the latest available
BSInstance unless the current task context clearly points at another
instance:
```bash ```bash
PYTHONPATH=src python -m plugin_helper instances PYTHONPATH=src .venv/bin/python -m plugin_helper instances
``` ```
4. Resolve the release source. 4. Resolve the release source.
@@ -69,7 +51,7 @@ notes/lock data.
For BeatMods bootstrap or verified packages, query BeatMods with a browser-like user agent: For BeatMods bootstrap or verified packages, query BeatMods with a browser-like user agent:
```bash ```bash
PYTHONPATH=src python - <<'PY' PYTHONPATH=src .venv/bin/python - <<'PY'
import json, urllib.request import json, urllib.request
from plugin_helper.beatmods import by_version_id, normalize_mods from plugin_helper.beatmods import by_version_id, normalize_mods
@@ -104,22 +86,13 @@ notes/lock data.
PY PY
``` ```
BeatMods dependency entries are mod-version ids. Resolve the selected mod's Follow the artifact policy for GitHub-first sourcing, BeatMods exceptions,
dependency closure before downloading. For each resolved package, prefer its and dependency closure. BeatMods CDN URLs are:
upstream `gitUrl` release artifacts when a matching release asset exists.
Fall back to BeatMods CDN only for inaccessible/missing upstream assets,
BeatMods-only packages, or framework/library dependencies. CDN URLs are:
```text ```text
https://beatmods.com/cdn/mod/<zipHash>.zip https://beatmods.com/cdn/mod/<zipHash>.zip
``` ```
For BSIPA bootstrap, expect the archive to contain root-relative `IPA/` and
`IPA.exe` files whether sourced from GitHub or BeatMods. Extract it into the
instance root and run `IPA.exe -n` under the same Proton environment used by
the smoketest. This creates/copies the root `winhttp.dll` and root `Libs/`
substrate that IPA needs.
For GitHub URLs, resolve the release from the user-provided repository or For GitHub URLs, resolve the release from the user-provided repository or
release URL only. release URL only.
@@ -148,13 +121,7 @@ release URL only.
unzip -l .state/instances/<instance>/downloads/<plugin-id>/<asset-name> unzip -l .state/instances/<instance>/downloads/<plugin-id>/<asset-name>
``` ```
Strategy guide: Use the install strategy guide in the artifact policy.
- `dll-to-plugins`: asset is a single `.dll` that belongs in `Plugins/`.
- `bsipa-zip`: zip top-level paths are only `IPA/`, `Libs/`, or `Plugins/`.
- `root-zip`: zip contains valid game-root paths outside the BSIPA top-level set. Use this for BSIPA/bootstrap archives because `IPA.exe`, `IPA.runtimeconfig*.json`, and root `winhttp.dll` are game-root files.
- `zip-to-pending`: only when the release is intended for `IPA/Pending/`.
- `manual`: do not use for installable releases.
6. Update the registry and lockfile. 6. Update the registry and lockfile.
@@ -188,9 +155,9 @@ release URL only.
Always pass `--state-dir .state` so the helper uses the repo-local downloaded asset: Always pass `--state-dir .state` so the helper uses the repo-local downloaded asset:
```bash ```bash
PYTHONPATH=src python -m plugin_helper --state-dir .state check --instance <instance> PYTHONPATH=src .venv/bin/python -m plugin_helper --state-dir .state check --instance <instance>
PYTHONPATH=src python -m plugin_helper --state-dir .state plan --instance <instance> --plugin <plugin-id> PYTHONPATH=src .venv/bin/python -m plugin_helper --state-dir .state plan --instance <instance> --plugin <plugin-id>
PYTHONPATH=src python -m plugin_helper --state-dir .state apply <generated-plan-path> PYTHONPATH=src .venv/bin/python -m plugin_helper --state-dir .state apply <generated-plan-path>
``` ```
Before applying, read or summarize the generated plan enough to confirm it changes only the intended plugin files. Before applying, read or summarize the generated plan enough to confirm it changes only the intended plugin files.
@@ -200,41 +167,15 @@ release URL only.
Confirm the installed file hashes match the plan or archive members: Confirm the installed file hashes match the plan or archive members:
```bash ```bash
PYTHONPATH=src python -m plugin_helper --state-dir .state state --instance <instance> PYTHONPATH=src .venv/bin/python -m plugin_helper --state-dir .state state --instance <instance>
PYTHONPATH=src python -m plugin_helper --state-dir .state check --instance <instance> PYTHONPATH=src .venv/bin/python -m plugin_helper --state-dir .state check --instance <instance>
PYTHONPATH=src python -m unittest discover -s tests PYTHONPATH=src .venv/bin/python -m compileall -q src tests
PYTHONPATH=src .venv/bin/python -m unittest discover -s tests
``` ```
Use `PYTHONPATH=src`; plain `python -m unittest` may fail in this source-layout repo. For live Beat Saber validation, follow the live-validation reference. Also
record when a BeatMods CDN artifact was used so it can be migrated to
After any successful apply that changes a live BSManager instance, always upstream GitHub later if possible.
run the documented live smoketest before the final response unless the user
explicitly says not to. Do not stop at helper check, unit tests, compile
checks, or file-hash verification for live installs. For live Beat Saber
validation, follow `docs/SMOKETEST.md`. Before starting the launch, announce
in agent chat how long the smoketest window will run for, using the current
duration from `docs/SMOKETEST.md` unless the user requested a different
duration. Do not rely on `timeout` to kill the full game process tree.
Prefer the documented foreground Proton launch with a background watchdog
that sleeps for the smoke window, then terminates Beat Saber by process
name. Confirm `Logs/_latest.log` has the expected IPA/plugin lines and
enough menu/UI initialization evidence for the plugin under test. If the
game remains open after the watchdog cleanup, say so and ask the user to
close it manually rather than leaving the turn with Beat Saber running.
For BSIPA/SongCore bootstrap, expected successful log lines include:
```text
Game version <version>
Loading plugins from Plugins and found <n>
Beat Saber IPA (BSIPA): <version>
SongCore (SongCore): <version>
```
Warnings about older mod target game-version metadata can be acceptable when
BeatMods verified that exact package for the target Beat Saber version, but
record them in the tracker or roadmap. Also record when a BeatMods CDN
artifact was used so it can be migrated to upstream GitHub later if possible.
9. Final response. 9. Final response.
@@ -8,6 +8,13 @@ description: Audit Beat Saber plugin-helper locks for available plugin updates a
Use this skill from the `plugin-helper` repo to produce an update audit, not to Use this skill from the `plugin-helper` repo to produce an update audit, not to
blindly update plugins. Keep public, private, and experimental sources distinct. blindly update plugins. Keep public, private, and experimental sources distinct.
Before auditing, read the shared policy references:
- [repo-workflow.md](../references/repo-workflow.md) for repo root, `.venv`, `PYTHONPATH=src`, dirty worktree handling, and validation commands.
- [state-and-profiles.md](../references/state-and-profiles.md) for `.state`, profiles, install identity, instance selection, and checkout locations.
- [artifact-policy.md](../references/artifact-policy.md) for GitHub/BeatMods/private-source/checksum policy.
- [live-validation.md](../references/live-validation.md) only when reviewing smoke-test notes or launch failures.
## Workflow ## Workflow
1. Confirm repo context: 1. Confirm repo context:
@@ -17,8 +24,9 @@ blindly update plugins. Keep public, private, and experimental sources distinct.
git status --short git status --short
``` ```
2. Choose the instance from the user request. If omitted, prefer `1.44.1` only 2. Choose the instance from the user request. If omitted, use the latest
when that is clearly the active migration context; otherwise list instances: available BSInstance unless the current task context clearly points at
another instance:
```bash ```bash
PYTHONPATH=src .venv/bin/python -m plugin_helper instances PYTHONPATH=src .venv/bin/python -m plugin_helper instances
@@ -36,7 +44,8 @@ blindly update plugins. Keep public, private, and experimental sources distinct.
verified metadata, skips `patreon/` and `discord/` sources, and marks local, verified metadata, skips `patreon/` and `discord/` sources, and marks local,
PR, manual, failed-trial, or pending-smoke entries as review items. PR, manual, failed-trial, or pending-smoke entries as review items.
4. Read the compatibility tracker before proposing updates for review items: 4. Read the active compatibility tracker before proposing updates for review
items. For the current migration notes, inspect:
```bash ```bash
sed -n '1,380p' docs/notes/install-and-verify-plugins-1.44.1.md sed -n '1,380p' docs/notes/install-and-verify-plugins-1.44.1.md
@@ -49,9 +58,8 @@ blindly update plugins. Keep public, private, and experimental sources distinct.
compatible source. compatible source.
5. For each public update candidate, inspect source notes before changing the 5. For each public update candidate, inspect source notes before changing the
lock. Prefer upstream GitHub release artifacts when available; use BeatMods lock. Follow the shared artifact policy for GitHub-first sourcing and
CDN only for verified fallback cases, BeatMods-only packages, inaccessible BeatMods fallback cases.
upstream assets, or framework/library dependencies.
6. Do not attempt automated public update checks for: 6. Do not attempt automated public update checks for:
@@ -0,0 +1,85 @@
# Beat Saber Artifact Policy
Use this policy for plugin install/update/bootstrap tasks and for audit reports
that discuss candidate artifacts.
## Source Priority
- Prefer upstream GitHub release artifacts for ordinary repository-backed
plugins.
- Use BeatMods primarily as compatibility, dependency, and verification
metadata.
- Use BeatMods CDN artifacts only for inaccessible upstream assets,
BeatMods-only packages, framework/library dependencies, or cases where no
matching upstream release asset exists.
- Skip paid/private Patreon, Discord, and closed-source sources during automated
public update checks. Report them as manual follow-up unless the user provides
the artifact and asks to manage it.
## Repository Guardrail
- For ordinary GitHub-hosted plugins, require an explicit GitHub repository,
release URL, or user-provided local planning note before selecting a release.
- If the user provided a repo URL but no release URL, query that exact repo's
releases and choose the most appropriate non-draft, non-prerelease release for
the target instance.
- If the user provided no repo or release URL for a plugin install/update, stop
and ask for one.
- Do not discover a different repository from web search, substitute a fork, or
infer the "correct" project from a similar package name.
- If the URL is a releases page, use that repo's release API and choose the
latest non-draft, non-prerelease release unless the user asks for a tag.
- If the URL is a tag URL, use that exact tag.
## BeatMods Exceptions
When the user explicitly asks to bootstrap a Beat Saber instance or install
verified mods without GitHub URLs, use BeatMods verified metadata to identify
compatible versions and dependency closure. Still prefer upstream GitHub assets
when BeatMods exposes a `gitUrl` and a matching release asset can be found.
Record the artifact source plus BeatMods `modVersion`, version id, `zipHash`,
dependencies, and supported game version in repo notes or lock data when
BeatMods metadata drives the selection.
BeatMods dependency entries are mod-version ids. Resolve the selected mod's
dependency closure before downloading.
## Checksums And Inspection
- Download artifacts into the selected helper state directory, normally:
```bash
<state_dir>/instances/<instance>/downloads/<plugin-id>/
```
- Record SHA-256 checksums for downloaded or built artifacts.
- Match the checksum against GitHub's `digest` when available.
- For BeatMods CDN artifacts, preserve BeatMods `zipHash` metadata and verify
the downloaded archive against the expected hash when the helper supports it.
- Inspect archive contents before selecting install strategy:
```bash
unzip -l <artifact>
```
## Install Strategy Guide
- `dll-to-plugins`: asset is a single `.dll` that belongs in `Plugins/`.
- `bsipa-zip`: zip top-level paths are only `IPA/`, `Libs/`, or `Plugins/`.
- `root-zip`: zip contains valid game-root paths outside the BSIPA top-level
set. Use this for BSIPA/bootstrap archives because `IPA.exe`,
`IPA.runtimeconfig*.json`, and root `winhttp.dll` are game-root files.
- `zip-to-pending`: only when the release is intended for `IPA/Pending/`.
- `manual`: do not use for installable releases.
## BSIPA Bootstrap
Treat BSIPA as a bootstrap phase. `bootstrap` installs the locked BSIPA archive
and records generated files. Ordinary plugin plans should depend on healthy
bootstrap state.
For BSIPA bootstrap archives, expect root-relative `IPA/` and `IPA.exe` files
whether sourced from GitHub or BeatMods. Extract into the instance root and run
`IPA.exe -n` under the same Proton environment used by the smoke test. This
creates or copies root `winhttp.dll` and root `Libs/` substrate files.
@@ -0,0 +1,43 @@
# Beat Saber Live Validation
Use this policy when a task changes or verifies a live BSManager instance.
## Smoke Test
- Follow `docs/SMOKETEST.md` for live game validation.
- Before starting Beat Saber, announce how long the smoke window will run, using
the current duration in `docs/SMOKETEST.md` unless the user requested a
different duration.
- Do not rely on `timeout` to kill the full game process tree.
- Prefer the documented foreground Proton launch with a background watchdog that
sleeps for the smoke window, then terminates Beat Saber by process name.
- After the run, confirm no Beat Saber process remains. If cleanup fails, say so
and ask the user to close it manually.
## Required After Live Apply
After any successful helper `apply` that changes a live BSManager instance, run
the documented live smoke test before the final response unless the user
explicitly says not to. Helper `check`, unit tests, compile checks, and file-hash
verification are useful but do not replace live validation.
## Logs
Inspect `Logs/_latest.log`, Unity `Player.log` when relevant, and the live
process command line before calling a black screen or launch failure a plugin
failure. Duplicate launch args such as repeated `--no-yeet fpfc` can trigger
fatal command-line parsing after BSIPA/plugin loading succeeds.
Expected successful BSIPA/SongCore lines include:
```text
Game version <version>
Loading plugins from Plugins and found <n>
Beat Saber IPA (BSIPA): <version>
SongCore (SongCore): <version>
```
Warnings about older mod target game-version metadata can be acceptable when
BeatMods verified that exact package for the target Beat Saber version. Record
them in the tracker or roadmap rather than treating them as automatic install
failure.
@@ -0,0 +1,52 @@
# plugin-helper Repo Workflow
Use these rules for all Beat Saber `plugin-helper` skills.
## Repo Context
- Work from the `plugin-helper` repo root.
- Confirm context before acting:
```bash
test -f pyproject.toml && test -d src/plugin_helper && test -d registry && test -d locks
git status --short
```
- The worktree may already be dirty. Treat existing changes as user work:
preserve them, do not revert them, and avoid unrelated formatting or metadata
churn.
- Use `rg`/`rg --files` for search.
## Python Commands
- Run helper commands with `PYTHONPATH=src`.
- Prefer `.venv/bin/python` when `.venv` exists; otherwise use `python`.
- For human-style inspection, prefer repo-local state:
```bash
PYTHONPATH=src .venv/bin/python -m plugin_helper --state-dir .state menu
```
## Validation
- After code changes in this repo, run:
```bash
PYTHONPATH=src .venv/bin/python -m compileall -q src tests
PYTHONPATH=src .venv/bin/python -m unittest discover -s tests
```
- For skill-only edits, also run `quick_validate.py` for each edited skill:
```bash
python /home/pleb/.codex/skills/.system/skill-creator/scripts/quick_validate.py .agents/skills/<skill-name>
```
- Plain `python -m unittest` can fail in this source-layout repo without
`PYTHONPATH=src`.
## Final Reporting
Report the commands actually run and their results. When a task changes repo
files, include a concise commit message suggestion unless the user already asked
for a commit.
@@ -0,0 +1,53 @@
# plugin-helper State And Profiles
Use these rules when selecting BSManager instances, state directories, and source
checkout locations.
## Instance Selection
- Prefer the Beat Saber instance the user names.
- If the user omits an instance, use the latest available BSInstance unless the
current task context or user notes clearly point at another instance.
- Discover available instances with the helper rather than assuming a hard-coded
game version:
```bash
PYTHONPATH=src .venv/bin/python -m plugin_helper instances
```
## State Directories
- Prefer repo-local `.state` for planned installs, update audits, downloaded
artifacts, and generated plans unless the user explicitly targets live default
state or another configured profile.
- For mounted Windows installs, prefer the shared Windows-partition state
directory configured in `plugin-helper.local.toml` when both roots contain the
same instance name.
- Keep target-specific managed state with the selected target root. Do not mix a
Linux install's `installed.json` with a Windows install's state unless the user
intentionally selected that shared state.
## Profiles
- Read `plugin-helper.local.toml` before choosing a configured profile:
```bash
sed -n '1,220p' plugin-helper.local.toml
PYTHONPATH=src .venv/bin/python -m plugin_helper --profile <profile-id> instances
```
- Treat the selected profile's `instances_root` and `state_dir` as a pair.
- When using `--profile`, prefer it over manually passing default BSManager paths.
## Source Checkouts
- Keep plugin source checkouts under `~/src/<owner>/<repo>` when a locked or
registry plugin has a GitHub source repo.
- Prefer checking out upstream `owner/repo` first, with `origin` pointing at
upstream.
- If a personal fork checkout already exists, preserve it as a remote named
`github` and set or add `origin` to the upstream repo instead of replacing
local work.
- For temporary PR/build work tied to a selected profile, use that profile's
`<state_dir>/build/<name>` when the skill explicitly calls for disposable
build checkouts.