From 26def9609daab7da834195806142cd49a34bbc63 Mon Sep 17 00:00:00 2001 From: pleb Date: Fri, 10 Jul 2026 08:42:55 -0700 Subject: [PATCH] Refactor agent skills --- .../skills/beatsaber-plugin-builder/SKILL.md | 33 +++--- .../references/linux-bsipa-build.md | 2 +- .../skills/beatsaber-plugin-manager/SKILL.md | 105 ++++-------------- .../beatsaber-plugin-update-auditor/SKILL.md | 20 +++- .agents/skills/references/artifact-policy.md | 85 ++++++++++++++ .agents/skills/references/live-validation.md | 43 +++++++ .agents/skills/references/repo-workflow.md | 52 +++++++++ .../skills/references/state-and-profiles.md | 53 +++++++++ 8 files changed, 291 insertions(+), 102 deletions(-) create mode 100644 .agents/skills/references/artifact-policy.md create mode 100644 .agents/skills/references/live-validation.md create mode 100644 .agents/skills/references/repo-workflow.md create mode 100644 .agents/skills/references/state-and-profiles.md diff --git a/.agents/skills/beatsaber-plugin-builder/SKILL.md b/.agents/skills/beatsaber-plugin-builder/SKILL.md index 1daf24d..c5040ed 100644 --- a/.agents/skills/beatsaber-plugin-builder/SKILL.md +++ b/.agents/skills/beatsaber-plugin-builder/SKILL.md @@ -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. +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. ## 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 ``` - 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 - `/build/`. Do not disturb unrelated dirty files. + In `plugin-helper`, run commands from repo root. Treat shared profile and + dirty-worktree policy as binding. 2. Resolve source. - For a GitHub PR, clone or reuse a checkout under the selected profile's - `/build`, add/fetch the upstream remote if needed, and check out - the PR head: + For a GitHub PR, clone or reuse a checkout according to the shared source + checkout policy, add/fetch the upstream remote if needed, and check out the + PR head: ```bash git clone https://github.com//.git /build/ @@ -37,7 +41,8 @@ For detailed Linux/BSMT behavior, read [linux-bsipa-build.md](references/linux-b git -C /build/ checkout 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. @@ -51,9 +56,11 @@ For detailed Linux/BSMT behavior, read [linux-bsipa-build.md](references/linux-b 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: + If the user did not specify an instance and the plugin does not require a + narrower version, use the latest available BSInstance. 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: ```bash PYTHONPATH=src .venv/bin/python -m plugin_helper --profile instances @@ -107,7 +114,7 @@ For detailed Linux/BSMT behavior, read [linux-bsipa-build.md](references/linux-b 8. Validate. - For skill edits inside this repo, run: + For skill edits inside this repo, run the shared skill validation plus: ```bash python /home/pleb/.codex/skills/.system/skill-creator/scripts/quick_validate.py .agents/skills/beatsaber-plugin-builder diff --git a/.agents/skills/beatsaber-plugin-builder/references/linux-bsipa-build.md b/.agents/skills/beatsaber-plugin-builder/references/linux-bsipa-build.md index cb94817..99f7045 100644 --- a/.agents/skills/beatsaber-plugin-builder/references/linux-bsipa-build.md +++ b/.agents/skills/beatsaber-plugin-builder/references/linux-bsipa-build.md @@ -43,7 +43,7 @@ Prefer machine-local configuration in `.csproj.user`: ```xml - /path/from/selected/profile/instances_root/1.44.1 + /path/from/selected/profile/instances_root/selected-instance ``` diff --git a/.agents/skills/beatsaber-plugin-manager/SKILL.md b/.agents/skills/beatsaber-plugin-manager/SKILL.md index 89bc5b4..32d5d6c 100644 --- a/.agents/skills/beatsaber-plugin-manager/SKILL.md +++ b/.agents/skills/beatsaber-plugin-manager/SKILL.md @@ -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. -## Hard Guardrail +Before acting, read the shared policy references: -For ordinary GitHub-hosted plugins, require an explicit GitHub repository or -release URL from the user's prompt or from a user-provided local planning note -before selecting any release. - -- 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. +- [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/bootstrap policy. +- [live-validation.md](../references/live-validation.md) for smoke tests, logs, and process cleanup. ## Workflow @@ -58,10 +38,12 @@ notes/lock data. 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 - PYTHONPATH=src python -m plugin_helper instances + PYTHONPATH=src .venv/bin/python -m plugin_helper instances ``` 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: ```bash - PYTHONPATH=src python - <<'PY' + PYTHONPATH=src .venv/bin/python - <<'PY' import json, urllib.request from plugin_helper.beatmods import by_version_id, normalize_mods @@ -104,22 +86,13 @@ notes/lock data. PY ``` - BeatMods dependency entries are mod-version ids. Resolve the selected mod's - dependency closure before downloading. For each resolved package, prefer its - 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: + Follow the artifact policy for GitHub-first sourcing, BeatMods exceptions, + and dependency closure. BeatMods CDN URLs are: ```text https://beatmods.com/cdn/mod/.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 release URL only. @@ -148,13 +121,7 @@ release URL only. unzip -l .state/instances//downloads// ``` - 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. + Use the install strategy guide in the artifact policy. 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: ```bash - PYTHONPATH=src python -m plugin_helper --state-dir .state check --instance - PYTHONPATH=src python -m plugin_helper --state-dir .state plan --instance --plugin - PYTHONPATH=src python -m plugin_helper --state-dir .state apply + PYTHONPATH=src .venv/bin/python -m plugin_helper --state-dir .state check --instance + PYTHONPATH=src .venv/bin/python -m plugin_helper --state-dir .state plan --instance --plugin + PYTHONPATH=src .venv/bin/python -m plugin_helper --state-dir .state apply ``` 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: ```bash - PYTHONPATH=src python -m plugin_helper --state-dir .state state --instance - PYTHONPATH=src python -m plugin_helper --state-dir .state check --instance - PYTHONPATH=src python -m unittest discover -s tests + PYTHONPATH=src .venv/bin/python -m plugin_helper --state-dir .state state --instance + PYTHONPATH=src .venv/bin/python -m plugin_helper --state-dir .state check --instance + 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. - - After any successful apply that changes a live BSManager instance, always - 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 - Loading plugins from Plugins and found - Beat Saber IPA (BSIPA): - SongCore (SongCore): - ``` - - 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. + 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 + upstream GitHub later if possible. 9. Final response. diff --git a/.agents/skills/beatsaber-plugin-update-auditor/SKILL.md b/.agents/skills/beatsaber-plugin-update-auditor/SKILL.md index 152dab5..bba5c08 100644 --- a/.agents/skills/beatsaber-plugin-update-auditor/SKILL.md +++ b/.agents/skills/beatsaber-plugin-update-auditor/SKILL.md @@ -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 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 1. Confirm repo context: @@ -17,8 +24,9 @@ blindly update plugins. Keep public, private, and experimental sources distinct. git status --short ``` -2. Choose the instance from the user request. If omitted, prefer `1.44.1` only - when that is clearly the active migration context; otherwise list instances: +2. Choose the instance from the user request. If omitted, use the latest + available BSInstance unless the current task context clearly points at + another instance: ```bash 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, 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 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. 5. For each public update candidate, inspect source notes before changing the - lock. Prefer upstream GitHub release artifacts when available; use BeatMods - CDN only for verified fallback cases, BeatMods-only packages, inaccessible - upstream assets, or framework/library dependencies. + lock. Follow the shared artifact policy for GitHub-first sourcing and + BeatMods fallback cases. 6. Do not attempt automated public update checks for: diff --git a/.agents/skills/references/artifact-policy.md b/.agents/skills/references/artifact-policy.md new file mode 100644 index 0000000..9904dcc --- /dev/null +++ b/.agents/skills/references/artifact-policy.md @@ -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 + /instances//downloads// + ``` + +- 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 + ``` + +## 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. diff --git a/.agents/skills/references/live-validation.md b/.agents/skills/references/live-validation.md new file mode 100644 index 0000000..196ca84 --- /dev/null +++ b/.agents/skills/references/live-validation.md @@ -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 +Loading plugins from Plugins and found +Beat Saber IPA (BSIPA): +SongCore (SongCore): +``` + +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. diff --git a/.agents/skills/references/repo-workflow.md b/.agents/skills/references/repo-workflow.md new file mode 100644 index 0000000..7892f1b --- /dev/null +++ b/.agents/skills/references/repo-workflow.md @@ -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/ + ``` + +- 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. diff --git a/.agents/skills/references/state-and-profiles.md b/.agents/skills/references/state-and-profiles.md new file mode 100644 index 0000000..9dfbbe5 --- /dev/null +++ b/.agents/skills/references/state-and-profiles.md @@ -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 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//` 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 + `/build/` when the skill explicitly calls for disposable + build checkouts.