
Migration Wizard
- 4 installs
- 145 repo stars
- Updated July 27, 2026
- bobmatnyc/claude-mpm
Migration Wizard is a Claude Code skill that defines a five-phase protocol for executing migration subskills which install and configure services.
About
Migration Wizard is a Claude skill defining the general protocol for executing migration subskills that install and configure services. Each subskill supplies declarative frontmatter data (check, install, verify commands) and this protocol tells the PM agent how to run it across five phases: user choice, detection, capability check, install, and verify. Developers use it to install services safely with a mandatory consent gate, idempotent detection, and host prerequisite checks before any install.
- Parent protocol for executing migration subskills that install and configure services
- Five-phase execution: user choice, detection, capability check, install, verify
- Phase 0 consent gate and Phase 1 idempotency detection are mandatory and never skipped
Migration Wizard by the numbers
- 4 all-time installs (skills.sh)
- Ranked #1,101 of 1,435 DevOps & CI/CD skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
migration-wizard capabilities & compatibility
- Capabilities
- service install · migration protocol · health check
- Use cases
- devops
What migration-wizard says it does
General protocol for executing migration skill wizards - service installation and configuration guides
**Always present the user with three options BEFORE any other action.**
Verify host prerequisites BEFORE attempting install.
npx skills add https://github.com/bobmatnyc/claude-mpm --skill migration-wizardAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 4 |
|---|---|
| repo stars | ★ 145 |
| Last updated | July 27, 2026 |
| Repository | bobmatnyc/claude-mpm ↗ |
What it does
Execute service-install migration subskills through a five-phase protocol with a consent gate and idempotent detection.
Who is it for?
PM agents executing declarative migration subskills that install and configure host services.
When should I use this skill?
Executing a migration subskill to install or configure a service.
What you get
A service installed and verified through a gated, idempotent five-phase protocol.
By the numbers
- 5 execution phases
- 11-field subskill frontmatter contract
Files
Migration Wizard Protocol
This skill defines the general protocol for executing migration skill wizards. It is the parent contract: every concrete migration subskill (e.g. trusty-services) provides declarative DATA in its frontmatter, and this protocol tells you HOW to execute that data.
Analogy: this skill is to migration subskills what runner.py is toindividualmigrate_*.pymodules insrc/claude_mpm/migrations/. The
subskill describes WHAT to install; this protocol describes HOW.
You (the PM agent) MUST load this protocol whenever you execute a migration subskill. Read the subskill's frontmatter and body for service-specific context (WHY, gotchas, post-install notes), then follow the five phases below verbatim.
---
Subskill Frontmatter Contract
A migration subskill declares the following fields in its YAML frontmatter:
| Field | Required | Purpose |
|---|---|---|
state_key | yes | Stable identifier for user-choice tracking |
services | yes | Human-friendly list of services being installed |
recommended | no | Whether to surface as recommended (default true) |
check_commands | yes | Phase 1 detection commands (each must exit 0 to skip install) |
health_checks | no | List of {url, service} daemons to probe after install |
system_requirements | no | {min_ram_gb, min_disk_gb, tools_required: [{name, check, install_hint}]} |
install_commands | yes (or install_script) | Phase 3 commands to run |
install_script | no | Path to a shell script (relative to subskill dir) |
verify_commands | yes | Phase 4 commands; each must exit 0 |
verify_scripts | no | Path(s) to verification scripts |
post_install_notes | no | Free-form text shown after Phase 5 |
The body of the subskill is FREE-FORM context: motivation, what to expect, known gotchas, configuration tips. It is not procedural — the procedure lives here.
---
Phase 0 — User Choice (MANDATORY FIRST STEP)
Always present the user with three options BEFORE any other action. Use the subskill's services list to phrase the prompt:
The<state_key>migration installs<services>. It is recommended but
optional. How would you like to proceed?
>
1. Install now — I'll walk you through it.
2. Remind me later — Defer for 24 hours.
3. Never — Permanently decline; I won't suggest this again.
Record the choice IMMEDIATELY before doing anything else:
# Option 1: proceed -> nothing recorded yet (complete is set in Phase 5)
# Option 2: defer
bash .claude/skills/migration-wizard/scripts/record-choice.sh <state_key> defer "user said: not now"
# Option 3: decline
bash .claude/skills/migration-wizard/scripts/record-choice.sh <state_key> decline "user declined permanently"If the user chose Defer or Never, confirm to the user and STOP. Do not proceed to Phase 1.
If the user chose Install now, continue.
NEVER skip Phase 0 even if Phase 1 detection would auto-complete the skill.
Phase 0 is the user-consent gate. Phase 1 is the idempotency gate.
---
Phase 1 — Detection
Run every command in the subskill's check_commands list. If all exit 0, the service is already installed. Auto-complete and stop:
bash .claude/skills/migration-wizard/scripts/record-choice.sh <state_key> complete "already installed"If the subskill defines health_checks, also probe each one using check-service-health.sh. The skill is "fully installed" only when both check_commands AND health_checks pass.
If detection passes fully, tell the user and stop the wizard.
If detection is partial (binary present but daemon down, etc.), note what's missing and continue to Phase 2 — the install commands should be idempotent and will repair the partial install.
---
Phase 2 — System Capability Check
Verify host prerequisites BEFORE attempting install.
General Capability Checks (Defined Here)
Run these regardless of subskill:
bash .claude/skills/migration-wizard/scripts/check-system-capabilities.sh \
--min-ram-gb <subskill.system_requirements.min_ram_gb || 4> \
--min-disk-gb <subskill.system_requirements.min_disk_gb || 2>Exits 0 if capable, 1 with a human-readable explanation if not.
Service-Specific Checks (Defined in Subskill)
Iterate system_requirements.tools_required. For each tool:
# Run tool.check; if non-zero, the tool is missing.
eval "<tool.check>"If a required tool is missing, show the user the tool's install_hint and stop the wizard — do not record a decline. The user may install the tool and re-run later.
If system resources are below the minimum, warn the user clearly. Offer:
1. Proceed anyway (record nothing; user accepts risk). 2. Decline permanently. 3. Defer for 24h.
Do not silently proceed when prerequisites fail.
---
Phase 3 — Installation
Delegate the actual install to the local-ops agent. Prefer install_script if present (preserves complex setup logic); fall back to running install_commands sequentially.
# Preferred: dedicated install script
bash .claude/skills/<subskill>/scripts/<install_script>
# Fallback: run install_commands in order
<install_command_1>
<install_command_2>Do not continue to Phase 4 until the install command returns success. If any install step fails:
1. Surface the error to the user verbatim. 2. Offer to retry, defer, or decline. 3. Do not record completion.
The subskill body may document known install failures (e.g., "Xcode CLT required on macOS"). Read it before reporting unknown errors.
---
Phase 4 — Verification
Re-run the subskill's verify_commands. Every command must exit 0. Then run any verify_scripts listed.
If verification fails:
1. Tell the user exactly which command failed. 2. Do not record completion. 3. Offer to retry installation or surface the error for manual investigation.
A partial install left in this state is correctly modeled as "still pending": the next session will re-detect and re-prompt.
---
Phase 5 — Completion
When all verification steps pass:
bash .claude/skills/migration-wizard/scripts/record-choice.sh <state_key> complete "installation verified"Then show the user a short summary:
- What was installed (the
serviceslist). - How to use it (whatever the subskill body documents).
- What changed in
.mcp.jsonor other config files. - Any
post_install_notesfrom the subskill.
Suggest restarting Claude Code to pick up any new MCP tools, and recommend claude-mpm doctor for verification.
---
Error Handling Summary
- User changes mind mid-wizard → treat as defer (24h) unless they say
"never". Always record something; never leave state in limbo.
- Unexpected error you can't resolve → file via
/mpm-bug, defer the
skill for 24h, tell the user.
- Phase 4 fails → do not record completion; the next session will
re-detect.
- User explicitly says "skip detection" → respect them; jump to Phase 3,
but warn that a re-install over a working install can break things.
---
Quick Reference: Shared Scripts
All located in .claude/skills/migration-wizard/scripts/:
record-choice.sh <state_key> <action> [reason]— wraps user_choices_clicheck-service-health.sh <url> [timeout]— HTTP health checkcheck-system-capabilities.sh [--min-ram-gb N] [--min-disk-gb N]— RAM + disklist-pending-migrations.sh— read~/.claude-mpm/pending-migrations.json
#!/usr/bin/env bash
# Probe a service's HTTP health endpoint.
#
# Usage: check-service-health.sh <url> [timeout_seconds]
#
# Exits 0 if the endpoint returns any 2xx response within the timeout
# (default 3 seconds), 1 otherwise. Output is suppressed; use exit codes.
#
# Examples:
# check-service-health.sh http://localhost:3038/health
# check-service-health.sh http://localhost:7878/health 5
set -uo pipefail
if [[ $# -lt 1 ]]; then
echo "Usage: $0 <url> [timeout_seconds]" >&2
exit 2
fi
URL="$1"
TIMEOUT="${2:-3}"
if ! command -v curl >/dev/null 2>&1; then
echo "error: curl not installed" >&2
exit 2
fi
# -f: fail on HTTP >=400, -s: silent, -o /dev/null: discard body,
# --max-time: hard cap on total request time.
if curl -fs -o /dev/null --max-time "${TIMEOUT}" "${URL}"; then
exit 0
fi
exit 1
#!/usr/bin/env bash
# Check generic host capabilities (RAM and free disk space).
#
# Usage:
# check-system-capabilities.sh [--min-ram-gb N] [--min-disk-gb N]
#
# Defaults: --min-ram-gb 4, --min-disk-gb 2.
#
# Exit codes:
# 0 All checks pass.
# 1 One or more checks failed (explanation printed to stderr).
# 2 Internal error (could not determine RAM or disk).
#
# Portable across macOS (BSD tools) and Linux (GNU tools).
set -uo pipefail
MIN_RAM_GB=4
MIN_DISK_GB=2
while [[ $# -gt 0 ]]; do
case "$1" in
--min-ram-gb)
MIN_RAM_GB="$2"
shift 2
;;
--min-disk-gb)
MIN_DISK_GB="$2"
shift 2
;;
--help|-h)
grep '^#' "$0" | sed 's/^# \{0,1\}//'
exit 0
;;
*)
echo "error: unknown option: $1" >&2
exit 2
;;
esac
done
# --- RAM detection ---
RAM_BYTES=""
case "$(uname -s)" in
Darwin)
RAM_BYTES="$(sysctl -n hw.memsize 2>/dev/null || true)"
;;
Linux)
if [[ -r /proc/meminfo ]]; then
# MemTotal is in kB
kb="$(awk '/^MemTotal:/ {print $2}' /proc/meminfo)"
if [[ -n "${kb}" ]]; then
RAM_BYTES=$((kb * 1024))
fi
fi
;;
esac
if [[ -z "${RAM_BYTES}" || "${RAM_BYTES}" -eq 0 ]]; then
echo "error: could not determine system RAM" >&2
exit 2
fi
RAM_GB=$((RAM_BYTES / 1024 / 1024 / 1024))
# --- Disk detection (free space in $HOME) ---
# df -k prints kilobytes; the "Available" column is 4 on macOS/Linux.
# Use $HOME as the target since that's where most installs land.
DISK_KB="$(df -k "${HOME}" 2>/dev/null | awk 'NR==2 {print $4}')"
if [[ -z "${DISK_KB}" ]]; then
echo "error: could not determine free disk space in ${HOME}" >&2
exit 2
fi
DISK_GB=$((DISK_KB / 1024 / 1024))
FAILED=0
if [[ "${RAM_GB}" -lt "${MIN_RAM_GB}" ]]; then
echo "RAM check FAILED: have ${RAM_GB}GB, need ${MIN_RAM_GB}GB" >&2
FAILED=1
fi
if [[ "${DISK_GB}" -lt "${MIN_DISK_GB}" ]]; then
echo "Disk check FAILED: have ${DISK_GB}GB free in ${HOME}, need ${MIN_DISK_GB}GB" >&2
FAILED=1
fi
if [[ "${FAILED}" -eq 0 ]]; then
echo "OK: RAM=${RAM_GB}GB (>=${MIN_RAM_GB}GB), Disk=${DISK_GB}GB free (>=${MIN_DISK_GB}GB)"
exit 0
fi
exit 1
#!/usr/bin/env bash
# Print the list of pending migration skill state_keys to stdout, one per line.
#
# Usage: list-pending-migrations.sh
#
# Reads ~/.claude-mpm/pending-migrations.json (produced by the
# check_migration_skills startup migration). If the file is missing or
# malformed, prints nothing and exits 0 — a missing file is normal during
# fresh installs.
set -uo pipefail
PENDING_FILE="${HOME}/.claude-mpm/pending-migrations.json"
if [[ ! -f "${PENDING_FILE}" ]]; then
exit 0
fi
# Prefer python3 (always available on this codebase). Fall back to a
# best-effort grep-based parser if Python is missing.
if command -v python3 >/dev/null 2>&1; then
python3 -c "
import json
import sys
try:
with open('${PENDING_FILE}') as f:
data = json.load(f)
for key in data.get('pending', []) or []:
if isinstance(key, str):
print(key)
except (json.JSONDecodeError, OSError):
sys.exit(0)
"
exit 0
fi
# Python-less fallback: extract values from a flat "pending" array.
grep -o '"[a-zA-Z0-9_-]\+"' "${PENDING_FILE}" 2>/dev/null \
| tr -d '"' \
| grep -v '^pending$\|^checked_at$' \
|| true
#!/usr/bin/env bash
# Record a migration skill user choice via the Python CLI module.
#
# Usage: record-choice.sh <state_key> <action> [reason]
#
# Actions: complete | decline | defer | status | reset
#
# This is a thin wrapper around `python3 -m claude_mpm.migrations.user_choices_cli`
# so that other shell scripts in the migration-wizard system have a stable
# command to call without needing to know the Python module path.
#
# Exits with the underlying CLI's exit code.
set -euo pipefail
if [[ $# -lt 2 ]]; then
echo "Usage: $0 <state_key> <complete|decline|defer|status|reset> [reason]" >&2
exit 1
fi
# Resolve a usable python interpreter. Prefer python3, fall back to python.
PYTHON_BIN="${PYTHON:-}"
if [[ -z "${PYTHON_BIN}" ]]; then
if command -v python3 >/dev/null 2>&1; then
PYTHON_BIN="python3"
elif command -v python >/dev/null 2>&1; then
PYTHON_BIN="python"
else
echo "error: no python3 or python on PATH" >&2
exit 2
fi
fi
exec "${PYTHON_BIN}" -m claude_mpm.migrations.user_choices_cli "$@"