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.
How this skill is triggered — by the user, by Claude, or both
Slash command
/xh:hoist-upgradeThis skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
Upgrade this Hoist project's `@xh/hoist` dependency between versions. Follow each phase in order.
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.
Render a structured upgrade summary directly in the chat. Do NOT write a report file -- the conversation is the artifact. If the developer wants it persisted, they can copy it or ask you to save it somewhere specific.
Print the following as a single Markdown response. Use short prose and lists; lean on tables only where they genuinely help (e.g. the hop overview). Skip optional sections when they don't apply.
## Hoist Upgrade Complete: @xh/hoist v{FROM} -> v{TO}
- **Hops:** {N} ({comma-separated hop list, e.g. v77 -> v78, v78 -> v79})
- **Branch:** {branch name}
- **Package manager:** {yarn | npm}
### Hop Overview
| Hop | Difficulty | Changes | Judgment Calls | Status |
|-----|------------|---------|----------------|--------|
| v{a} -> v{b} | {TRIVIAL/LOW/MEDIUM/HIGH} | {n} | {n} | {ok / failed} |
| ...
### Per-Hop Detail
#### v{a} -> v{b} ({difficulty}, guide: {upgrade-notes | CHANGELOG})
**Mechanical changes applied:**
- `{file}` -- {what changed}
- ...
**Judgment calls (require your review):**
- **{item}** -- {one-line description}
- Files: {comma-separated}
- Guide recommendation: {recommendation}
{Repeat per hop. Omit empty subsections.}
### Verification
- TypeScript (`tsc --noEmit`): {pass | fail with brief detail}
- Lint: {pass | fail with brief detail}
- hoist-react CLI (`npx hoist-docs index`): {ok | error}
- hoist-react MCP reconnect: {reconnected | skipped | failed}
- hoist-core CLI (if launchers refreshed): {ok | error | N/A}
### hoist-core Changes
{Include only if hoistCoreVersion was bumped.}
- {old} -> {new} (required by {hop or guide reference})
- Launchers: {refreshed via installHoistCoreTools, ping verified | not previously installed -- skipped}
- {If significant server-side code was detected in Phase 1, add a one-line note that
server-side review is recommended.}
### Client Plugin Notes
{Include only if client plugins were detected.}
- `{plugin}`: {old} -> {new or unchanged} -- {notes}
### Next Steps
- [ ] Review the judgment calls above and apply as appropriate
- [ ] Test affected features (especially anything in judgment calls)
- [ ] Run the app and verify core functionality
{Include if hoist-core was bumped:}
- [ ] Review hoist-core release notes if this project has significant server-side code
{Include if hoistCoreVersion >= 39.0 AND bin/hoist-core-mcp does NOT exist:}
- [ ] Install the hoist-core MCP+CLI tools now that you're eligible (>= v39.0):
run `/xh:onboard-app` -- it will detect the new eligibility and offer to install
{Include if client plugins were detected:}
- [ ] Verify client plugin compatibility with the upgraded Hoist version
- [ ] Open / merge the pull request for this upgrade branch
Be honest in the verification section -- if tsc or lint failed and you and the developer
worked through the failures, summarize what was resolved. If something is still broken at
report time, say so plainly so the developer doesn't merge a half-green branch.
npx claudepluginhub xh/hoist-ai --plugin xhProvides behavioral guidelines to reduce common LLM coding mistakes, focusing on simplicity, surgical changes, assumption surfacing, and verifiable success criteria.
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.
Creates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.