From xh
Upgrade a Hoist app's `@xh/hoist` dependency across one or more major versions. Reads per-version upgrade guides, auto-applies mechanical code migrations, flags judgment calls, bumps `hoistCoreVersion` (and refreshes the hoist-core MCP+CLI launchers if previously installed), and produces a comprehensive upgrade report.
npx claudepluginhub xh/hoist-ai --plugin xhThis skill is limited to using the following tools:
Upgrade this Hoist project's `@xh/hoist` dependency between versions. Follow each phase in order.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Checks Next.js compilation errors using a running Turbopack dev server after code edits. Fixes actionable issues before reporting complete. Replaces `next build`.
Upgrade this Hoist project's @xh/hoist dependency between versions. Follow each phase in order.
Gather project information needed to plan and execute the upgrade.
Check $ARGUMENTS for an optional target version (e.g. 81.0.0 or v81). If present, normalize
it: strip any leading v, store as the target version for Phase 2. If no argument is provided,
the skill will prompt the developer to choose a target in Phase 2.
Check which lockfile exists in client-app/:
yarn.lock -- use yarn (e.g. yarn install, yarn why, yarn lint)package-lock.json -- use npm (e.g. npm install, npm ls, npm run lint)Store the detected package manager. All frontend commands in subsequent phases should be run
from client-app/ using this package manager.
Read client-app/package.json. Find @xh/hoist in dependencies and extract the current
version. Handle version strings like ^82.0.0-SNAPSHOT -- extract the numeric portion
(e.g. 82.0.0).
If @xh/hoist is not a direct dependency, it may be pulled in transitively via a client plugin.
Run from client-app/:
yarn why @xh/hoistnpm ls @xh/hoistIf neither approach finds @xh/hoist, inform the user:
"This does not appear to be a Hoist project --
@xh/hoistwas not found as a direct or transitive dependency."
Then stop.
Run:
git status --porcelain
If output is non-empty, warn the developer:
"Your working tree has uncommitted changes. Please commit or stash them before running the upgrade to ensure a clean rollback point if needed."
Do NOT proceed with any modifications until the working tree is clean.
Read gradle.properties at the project root. Extract the hoistCoreVersion value.
If the version is not set directly (e.g. it is inherited from a client-specific Grails plugin
dependency), check build.gradle for the plugin dependency and note the transitive hoist-core
version if determinable.
Assess server-side significance: Check CLAUDE.md for notes about server-side complexity.
Also scan the Grails app package (e.g. grails-app/controllers/, grails-app/services/) for
custom controllers and services. If extensive custom server code is present, note this -- it
means hoist-core version bumps warrant extra attention in the upgrade report.
Scan client-app/package.json dependencies for packages that are NOT @xh/hoist but appear to
be Hoist-related client plugins (e.g. @client/hoist-plugin, @client/hoist-*).
Also read CLAUDE.md for any documented plugin-to-Hoist version mapping or plugin notes.
When a client plugin is detected, note the package name, current version, and any version mapping information for use in Phase 2 planning.
Present the upgrade plan for developer confirmation. Do NOT make any changes until the developer confirms.
If a target version was provided via arguments in Phase 1, use it.
If no target version was specified, query npm for available versions:
npm view @xh/hoist versions --json
npm view is a registry-query command -- it works in any Node.js environment regardless of
which package manager the project uses, since npm ships with Node itself. No need to route
through the project's detected manager here.
Filter the results to stable releases only -- versions matching x.y.z with no prerelease
suffix. Exclude versions with -SNAPSHOT, -alpha, -beta, -rc, or any other prerelease tag.
XH publishes many SNAPSHOT versions to npm during development -- these should never be suggested
as upgrade targets.
Filter to versions newer than the currently installed version and present a structured list:
Available @xh/hoist versions (you have v{current}):
v79.0.0
v80.0.0
v80.1.0
v81.0.0 <- latest
What version would you like to upgrade to?
Wait for the developer to choose before continuing.
Each major version between current and target is a separate hop. Example: v77 -> v81 produces the sequence [v77->v78, v78->v79, v79->v80, v80->v81].
For minor version jumps within the same major version (e.g. v80.0.0 -> v80.1.0), treat that as a single hop.
For each hop in the sequence, check if a dedicated upgrade guide exists. Use Glob to look for:
client-app/node_modules/@xh/hoist/docs/upgrade-notes/v*-upgrade-notes.md
Match each hop's target version against the available files. If a guide does NOT exist for a particular hop's target version (versions before v73 will not have one), note that hop as "CHANGELOG-only" and alert the developer:
"Note: No dedicated upgrade guide exists for v{target}. This hop will use CHANGELOG entries only, and guidance may be less thorough."
If client plugins were detected in Phase 1, present the detection:
### Client Plugins Detected
| Plugin | Current Version | Hoist Version Mapping |
|--------|----------------|----------------------|
| {plugin name} | {version} | {mapping from CLAUDE.md, or "No mapping found"} |
How should I handle the plugin version during this upgrade?
- Bump to a specific version?
- Leave unchanged?
- Other guidance?
Do not proceed until the developer confirms the plugin approach.
## Upgrade Plan: @xh/hoist v{current} -> v{target}
| Hop | Guide Available | Difficulty |
|-----|-----------------|------------|
| v77 -> v78 | Yes (upgrade notes) | TBD (read during execution) |
| v78 -> v79 | Yes (upgrade notes) | TBD |
| ...
- **Branch:** upgrade/hoist-v{current}-to-v{target} (or existing branch if found)
- **Commits:** One per version hop
- **hoist-core:** {current version from gradle.properties}
- **Server complexity:** {Minimal (stock) | Significant (custom controllers/services)}
- **Client plugins:** {Detected plugins, or "None detected"}
- **Package manager:** {detected package manager}
Ask: "Proceed with this upgrade plan? (yes/no)"
Wait for confirmation before making any changes.
For each version hop in the sequence, apply the upgrade. Never commit directly to main or develop.
Check for existing branches matching upgrade/hoist-* or hoist-upgrade-* patterns:
git branch --list "upgrade/hoist-*" "hoist-upgrade-*"
If a matching branch exists, ask the developer if they want to reuse it.
If no match (or developer declines reuse), create a new branch:
git checkout -b upgrade/hoist-v{current}-to-v{target}
Verify the current branch is NOT main or develop before any commits.
Update the @xh/hoist version in client-app/package.json dependencies to the hop's target
version (e.g. "@xh/hoist": "^{target}").
Run the detected package manager's install command from client-app/ to update the lockfile
and install the new version.
Important: The upgrade notes for version N ship with version N. They are only available on the filesystem after installing the target version.
Use the Read tool to read upgrade notes directly from the filesystem:
client-app/node_modules/@xh/hoist/docs/upgrade-notes/v{TARGET}-upgrade-notes.md
Do NOT use MCP hoist-search-docs for upgrade notes. The MCP server may still be serving
the previous version's content after install. The Read tool always reflects the installed
version.
For versions WITHOUT upgrade notes (pre-v78): Read client-app/node_modules/@xh/hoist/CHANGELOG.md and
parse the Breaking Changes section for the target version. Alert the developer:
"No dedicated upgrade guide exists for this version. Using CHANGELOG breaking changes section. Guidance may be less thorough for this hop."
Read the upgrade guide carefully. For each migration step:
Mechanical changes (renames, import updates, CSS class changes):
Judgment calls (behavior changes, multiple replacement options, architectural decisions):
When migration involves API changes and you need to verify new API shapes, prefer the
before/after code examples in the upgrade guide. MCP API lookups (hoist-get-symbol,
hoist-search-symbols) may reflect the previous version until the MCP server is reconnected.
Parse the upgrade guide's "Prerequisites" section for hoist-core version requirements (e.g. "hoist-core >= v36.1").
If a requirement is found, compare against the current hoistCoreVersion from
gradle.properties (read in Phase 1).
If the current version is below the requirement:
hoistCoreVersion in gradle.properties to the required version.bin/hoist-core-mcp exists at the project root. If it does, the launchers embed an
absolute path to a version-suffixed JAR (e.g. hoist-core-mcp-{old}-all.jar) and are now
stale. Re-run:
./gradlew installHoistCoreTools
This refreshes the launchers to point at the new version's JAR. Verify with
./bin/hoist-core-docs ping (returns hoist-core CLI is running.). Note the refresh in
the upgrade report.hoistCoreVersion
is >= 39.0 AND bin/hoist-core-mcp does NOT exist (i.e., the install task was never run
here), the user is now eligible for the hoist-core MCP server + hoist-core-docs /
hoist-core-symbols CLI tools (introduced in v39.0). Add a "Next Steps" item to the upgrade
report: "Install the hoist-core MCP+CLI tools by running /xh:onboard-app -- onboarding
will detect the new eligibility and offer to install."If a client plugin was detected and the developer confirmed a version strategy in Phase 2:
client-app/package.json according to the confirmed strategyclient-app/ after the plugin version bumpgit add -A
git commit -m "Upgrade @xh/hoist v{FROM} -> v{TO}"
After each hop, display a brief status showing progress through the sequence:
## Upgrade Progress: v{start} -> v{end}
[completed] v77 -> v78 (TRIVIAL) -- N changes applied, M judgment calls
[in progress] v78 -> v79 -- in progress...
[pending] v79 -> v80 -- pending
After ALL hops are complete, run verification. The CLI surface is the always-on baseline (it
reads from node_modules and always reflects the upgraded version); MCP reconnect is
opportunistic and safe to skip in environments that block MCP.
hoist-react CLI (universal, always run). From client-app/, run:
npx hoist-docs index
This reads from client-app/node_modules/@xh/hoist/... and always reflects the just-installed
version. A clean docs index print confirms the upgraded surface is reachable. Surface any
errors before continuing.
hoist-react MCP reconnect (only if MCP is part of your workflow). The MCP server is still serving the pre-upgrade version's types and docs. Prompt the developer:
"If you use MCP in this environment, please run
/mcpin Claude Code to reconnect the hoist-react server, then say 'continue'. If you don't use MCP (for example, in MCP-blocked enterprise environments), say 'skip' -- the CLI surface above is the working path and already reflects the upgrade."
After 'continue': call mcp__hoist-react__hoist-ping to confirm. After 'skip', or if the ping
fails or the tool isn't in your context, proceed without error -- the CLI verification above is
sufficient.
hoist-core CLI (only if launchers were refreshed in Phase 3e). If Phase 3e re-ran
installHoistCoreTools, run:
./bin/hoist-core-docs ping
Expect hoist-core CLI is running. This confirms the refresh produced working launchers
pointing at the new JAR. Surface any errors before continuing.
Run from client-app/:
npx tsc --noEmit
Report pass/fail.
Run the project's lint command from client-app/ using the detected package manager.
Report pass/fail.
If the final version's upgrade guide includes a verification checklist, present it to the developer and work through each item.
If verification fails, present the errors and work with the developer to resolve them before proceeding to the report phase.
For multi-hop upgrades where all hops are LOW or TRIVIAL difficulty, batch all verification at the end. For hops rated MEDIUM or higher, consider running intermediate TypeScript compilation checks after those hops to catch issues before they compound. Use your judgment based on the difficulty ratings read from the upgrade guides.
Use Glob to find the template:
**/hoist-upgrade/templates/upgrade-report.md
Read the template from the matched path.
Fill in the template with all data collected during the upgrade:
Write the completed report to:
docs/upgrade-reports/upgrade-v{FROM}-to-v{TO}-{YYYY-MM-DD}.md
Create the docs/upgrade-reports/ directory if it does not exist.
Show a condensed summary in the terminal:
## Upgrade Complete: @xh/hoist v{FROM} -> v{TO}
- **Versions upgraded:** {hop count}
- **Changes applied:** {total count}
- **Judgment calls:** {count} items requiring your review
- **Verification:** CLI: {ok/fail}, MCP: {reconnected/skipped/failed}, tsc: {status}, lint: {status}
- **hoist-core:** {bumped from vXX to vYY -- launchers refreshed | bumped from vXX to vYY (no launchers to refresh) | unchanged}
- **hoist-core MCP+CLI install eligibility:** {now eligible (>= v39.0) -- run /xh:onboard-app to install | already installed | not eligible (< v39.0) | N/A}
- **Full report:** docs/upgrade-reports/upgrade-v{FROM}-to-v{TO}-{YYYY-MM-DD}.md
Check if the gh CLI is available:
gh --version
If available, offer to create a pull request:
"Would you like me to create a pull request for this upgrade? (yes/no)"
If yes, use gh pr create with a title like "Upgrade @xh/hoist v{FROM} -> v{TO}". For the
body, lead with the terminal summary so a reviewer can scan key facts in seconds, then a
separator, then the full content of the upgrade report file (read it back with the Read
tool and inline it). This keeps the PR self-contained -- a reviewer doesn't need to check out
the branch to see the full per-hop changes and judgment calls.
If gh is not available, skip this step silently.