Migrate from legacy to plugin form
When this skill runs, walk the user through moving from legacy install to plugin install. The migration is non-destructive to project state: canvas, diamonds, memory, decision log, evals, and active metrics are preserved. Only framework reference content (skills, hooks, engine, scripts, schemas, etc.) is removed from .claude/ — that content now ships in the plugin cache.
Step 1: Detect current install form
Check the project's .claude/ directory:
test -d "$CLAUDE_PROJECT_DIR/.claude/skills" && echo "legacy framework files present" || echo "no legacy framework files"
test -d "$CLAUDE_PROJECT_DIR/.claude/canvas" && echo "project state present" || echo "no project state"
Three states:
- Legacy install (skills/ + canvas/ both present): proceed to Step 2.
- Already migrated (canvas/ present, skills/ absent): tell the user "This project is already on plugin form. No migration needed." and exit.
- Empty (neither present): tell the user "No Mycelium install detected. Run
/mycelium:startto bootstrap a fresh plugin install." and exit.
Step 2: Verify the plugin is installed
Ask the user to confirm the plugin is installed before deleting legacy framework files. If they don't have the plugin yet, deleting framework files would leave them with no Mycelium at all.
Tell them to run inside Claude Code:
/plugin marketplace add haabe/mycelium
/plugin install mycelium@haabe-mycelium
Then ask: "Is the plugin installed now?" Wait for confirmation before continuing. Acceptable answers: "yes", "installed", "done", or running /mycelium:ping to verify the plugin loaded (returns a deterministic marker if so).
If the user says no or seems uncertain, exit and tell them to come back after installing.
Step 3: Verify a clean working tree
The migration is reversible via git, so the project must be a git repo with a clean working tree before proceeding. Run:
cd "$CLAUDE_PROJECT_DIR"
git rev-parse --is-inside-work-tree # must succeed
git diff-index --quiet HEAD -- # must succeed (no uncommitted changes)
If either check fails, tell the user:
"Migration is reversible via git, so I need a clean working tree first. Either commit or stash your current changes:
git add -A && git commit -m 'Pre-migration snapshot'Then re-run
/mycelium:migrate-from-legacy."
Then exit.
Step 4: Show the user what will happen
Before running the migration, render this to the user:
Migration plan — legacy → plugin form
Will DELETE (framework reference content, now lives in plugin cache):
.claude/skills/,.claude/engine/,.claude/hooks/.claude/scripts/,.claude/schemas/,.claude/domains/.claude/orchestration/,.claude/templates/,.claude/tests/.claude/agents/(if present).claude/jit-tooling/*(exceptactive-metrics.yml).claude/harness/*(exceptdecision-log.md,warnings-log.md)Will PRESERVE (project state):
.claude/canvas/(your populated canvases).claude/diamonds/active.yml(diamond state).claude/memory/(corrections, patterns, journals).claude/evals/(eval scenarios + dogfood reports).claude/state/(runtime state, if present).claude/harness/decision-log.md,warnings-log.md.claude/jit-tooling/active-metrics.yml.claude/settings.local.json(your local overrides)Project root files (CLAUDE.md, README.md, AGENTS.md, LICENSE, CONTRIBUTORS.md, etc.) are NOT touched.
Skill invocations change:
/interviewbecomes/mycelium:interview. Tab-completion (/myc<Tab>) expands the prefix; natural-language invocation ("run mycelium interview") also routes correctly. No alias mechanism in Anthropic's plugin spec.Reversible:
git reset --hard HEADbefore committing returns to pre-migration state.Continue?
Wait for explicit "yes." Anything else aborts.
Step 5: Run the migration script
The legacy .claude/scripts/upgrade.sh shipped with the user's project (from their last legacy refresh) supports a --migrate-to-plugin flag. Invoke it:
cd "$CLAUDE_PROJECT_DIR"
bash .claude/scripts/upgrade.sh --migrate-to-plugin
If the user's upgrade.sh is older than v0.20.10 (predates the migration flag), it will fail with "Unknown flag: --migrate-to-plugin". In that case, tell them to first refresh their legacy install with the standard upgrade:
bash .claude/scripts/upgrade.sh
This pulls the latest legacy framework content (including the migration-aware upgrade.sh). Then re-invoke /mycelium:migrate-from-legacy.
The script is interactive when run from a terminal — it asks for confirmation before deleting. When invoked from this skill in Claude Code's Bash tool, the script's [ -t 0 ] check fails (no TTY); it proceeds without prompting unless MYCELIUM_MIGRATE_AUTO=cancel is set. The user has already confirmed in Step 4, so non-interactive proceed is correct here.
If the script exits with a non-zero status, surface the error to the user and stop. Do not attempt manual cleanup — the script's atomic-deletion approach is the safer path; partial cleanup leaves the project in an unknown state.
Step 6: Verify project state survived
After the script reports "Migration complete", run these checks:
test -f .claude/diamonds/active.yml && echo "diamonds preserved"
test -d .claude/canvas && echo "canvas preserved"
test -f .claude/memory/corrections.md && echo "corrections preserved"
test -f .claude/harness/decision-log.md && echo "decision-log preserved"
test ! -d .claude/skills && echo "legacy framework deleted"
test ! -d .claude/engine && echo "legacy engine deleted"
Then invoke /mycelium:diamond-assess to read the canvas and diamonds — this exercises the plugin reading project state through the new path resolution. If /mycelium:diamond-assess returns a coherent assessment, the migration is verified working.
If any project-state check fails, that's a bug in the migration script — surface it loudly to the user and recommend git reset --hard HEAD to revert.
Step 7: Settings hooks block (manual cleanup)
The legacy migration script (.claude/scripts/upgrade.sh --migrate-to-plugin) warns if .claude/settings.json contains a "hooks" block. That check only covers settings.json, not settings.local.json — which is actually the more common location for hook registrations in real-world installs (the local-overrides convention). So this skill takes ownership of checking both files.
Run the dual-grep check:
cd "$CLAUDE_PROJECT_DIR"
for sf in .claude/settings.json .claude/settings.local.json; do
if [ -f "$sf" ] && grep -Eq '^\s*"hooks"\s*:' "$sf"; then
echo "WARN: legacy hooks block found in $sf"
fi
done
For each file the grep flags, tell the user — with the specific file path — to open it and remove the top-level "hooks": { ... } block. In plugin form, hooks are wired via ${CLAUDE_PLUGIN_ROOT}/hooks/hooks.json automatically; any settings-level hooks block now points at the just-deleted .claude/hooks/ tree.
Symptom if skipped: every turn emits non-blocking errors like bash: .../.claude/hooks/gate.sh: No such file or directory (PreToolUse, PostToolUse, Stop). The tool calls still succeed because the errors are non-blocking, but the noise is real and points back to this step.
Also surface (independent of the grep): if either settings file contains a "customCommands" block referencing legacy /foo skill names, those need updating to /mycelium:foo.
This step is manual-edit (the SKILL flags but doesn't auto-rewrite) because settings files contain user-customized content alongside the legacy hooks block, and the SKILL shouldn't risk clobbering user-owned config.
Step 8: Final commit
Suggest the commit message:
git add -A
git commit -m "chore: migrate from legacy Mycelium to plugin form"
Then tell the user: