---
name: eck:migrate-project
version: "0.7.4"
description: Onboard an existing unmanaged project into the evolv-coder-kit ecosystem with assessment, interview, and selective infrastructure deployment.
disable-model-invocation: false
---

# Migrate Project Workflow

Onboard an existing project that has no (or partial) evolv-coder-kit infrastructure. Assesses existing `.claude/` files, interviews the user for missing configuration, applies catalog infrastructure while preserving existing files, and produces a summary.

---

## Visual Framework

Follow these conventions for all terminal output displayed to the user via the Bash tool.

### Output Mode Awareness

Before producing output, read the user's preferred output mode:

```bash
cat $ECK_HOME/user-preferences.json 2>/dev/null
```

Extract the `outputMode` field and adapt verbosity:

- **guided** — Add explanatory prose after key steps. Describe what is happening and why.
- **standard** (default) — Balanced. Show steps with brief context for non-obvious decisions.
- **concise** — Steps and summary box only. No prose, no explanations.

If the file is missing or `outputMode` is absent, use **standard**.

### ANSI Colors

Declare these variables at the top of **every** Bash tool call (shell state does not persist between calls):

```bash
source $ECK_HOME/colors.sh
```

Every color sequence **must** end with `${RESET}`. No exceptions.

### Stage Banners

Mark major stage transitions with a bold banner. One blank line before and after.

```bash
echo ""
printf '%b\n' "${ORANGE}${BOLD}STAGE NAME${RESET}"
echo ""
```

### Status Symbols

| Symbol | Meaning          | Color       |
| ------ | ---------------- | ----------- |
| `[*]`  | Active / running | `${CYAN}`   |
| `[x]`  | Completed        | `${GREEN}`  |
| `[!]`  | Error            | `${RED}`    |
| `[-]`  | Skipped          | `${DIM}`    |
| `[>]`  | In progress      | `${YELLOW}` |
| `[ ]`  | Pending          | `${DIM}`    |

```bash
printf '%b\n' "${GREEN}[x]${RESET} Step completed"
printf '%b\n' "${RED}[!]${RESET} Something failed"
```

No emoji in output. Use only these bracket symbols for status.

### Summary Boxes

Display at checkpoints and at the end of the skill. One blank line before and after.

```bash
echo ""
printf '%b\n' "${ORANGE}${BOLD}Title${RESET}"
echo ""
printf '%b\n' "Label: Value"
echo ""
```

### Error Format

```bash
printf '%b\n' "${RED}[!]${RESET} Error message here"
printf '%b\n' "    ${DIM}Recovery guidance here.${RESET}"
```

### Spacing Rules

- One blank line before and after stage banners and summary boxes.
- No blank lines within step lists.
- Maximum output line width: 70 characters.

### Statusline Stage Updates

At the **start** of each stage, update the statusline:

```bash
bash $ECK_HOME/update-stage.sh "{Statusline text from table}"
```

At **skill completion** (success or error), reset:

```bash
bash $ECK_HOME/update-stage.sh
```

---

## Task Registration

| Stage | Subject                 | Active Form               | Statusline      |
| ----- | ----------------------- | ------------------------- | --------------- |
| 1     | Stage 1: Pre-Flight     | Verifying prerequisites   | Preflight (1/5) |
| 2     | Stage 2: Assessment     | Assessing project         | Assess (2/5)    |
| 3     | Stage 3: Interview      | Conducting interview      | Interview (3/5) |
| 4     | Stage 4: Infrastructure | Installing infrastructure | Infra (4/5)     |
| 5     | Stage 5: Summary        | Generating summary        | Summary (5/5)   |

## Usage

```bash
/eck:migrate-project                    # Migrate current directory
/eck:migrate-project <project-path>     # Migrate specific project
```

---

## Stage 1: Pre-Flight

### Inputs

- `$ARGUMENTS` — optional target project path (defaults to current directory)
- `$ECK_HOME/global-catalog.yaml`
- `$ECK_HOME/` template directory

### Activities

### Requirements

- Write access to target project directory
- Read access to catalog templates at: `$ECK_HOME/`
- Read access to canonical catalog at: `$ECK_HOME/global-catalog.yaml`

### Verification

```bash
# Check catalog exists
ls $ECK_HOME/global-catalog.yaml

# Check target directory exists
ls {TARGET_PATH}
```

**If catalog not found:**

```bash
printf '%b\n' "${RED}[!]${RESET} Catalog templates not found at $ECK_HOME/"
printf '%b\n' "    ${DIM}Run: npx @evolvconsulting/evolv-coder-kit --global${RESET}"
```

**If target has full infrastructure (`.claude/project-catalog.yaml` exists):**

```bash
printf '%b\n' "${YELLOW}[>]${RESET} This project already has a deployed catalog."
printf '%b\n' "    ${DIM}It appears to be a managed project.${RESET}"
printf '%b\n' "    ${DIM}Use /eck:audit-current-project for health checks${RESET}"
printf '%b\n' "    ${DIM}or /eck:pull-from-global-catalog to apply updates.${RESET}"
```

Offer to proceed anyway if the user confirms.

### Outputs

- Resolved target project path; catalog confirmed accessible; project managed-state checked

### Exit Criteria

- Catalog templates found; target directory exists; skill may proceed (or user has confirmed override)

---

## Stage 2: Assess Existing Infrastructure

### Inputs

- Target project directory from Stage 1
- `$ECK_HOME/global-catalog.yaml` (catalog component list)

### Activities

### Scan Target

Enumerate everything in `<TARGET_PATH>/.claude/` (if it exists):

```bash
# Check for .claude/ directory
ls -la {TARGET_PATH}/.claude/

# List all files recursively
find {TARGET_PATH}/.claude/ -type f 2>/dev/null
```

Also check for root infrastructure files:

- `CLAUDE.md`
- `development-workflow.md`
- `.mcp.json`

### Build Inventory

For each found file, record:

- Relative path
- File size
- Whether it has a catalog counterpart

### Produce Assessment

Display as branded output with status symbols:

```bash
source $ECK_HOME/colors.sh

echo ""
printf '%b\n' "${ORANGE}${BOLD}Migration Assessment${RESET}"
echo ""
# For each category, use status symbols:
# [x] = found and will keep, [>] = found and will merge,
# [*] = will add from catalog, [-] = not applicable
printf '%b\n' "${GREEN}[x]${RESET} CLAUDE.md               Found -- keep"
printf '%b\n' "${YELLOW}[>]${RESET} .claude/settings.json   Found -- merge"
printf '%b\n' "${CYAN}[*]${RESET} .claude/hooks/          Missing -- add {N} templates"
printf '%b\n' "${DIM}[-]${RESET} .claude/primitives/     Not applicable"
echo ""
printf '%b\n' "  ${DIM}Files to preserve:${RESET} {N}"
printf '%b\n' "  ${DIM}Files to add:${RESET}      {N}"
```

### Outputs

- Infrastructure inventory: files to preserve, merge, and add; assessment displayed to user

### Exit Criteria

- Existing `.claude/` contents enumerated and categorized against the catalog

---

## Stage 3: Interview

### Inputs

- Assessment results from Stage 2 (known vs unknown values)
- Existing `project-constants.md`, `CLAUDE.md`, `settings.json` (if present)

### Activities

Conduct a lighter interview than `/eck:new-project` — only ask about what's missing or unclear.

### Auto-Detect from Existing Files

If `project-constants.md` exists, extract values from it:

- `<PROJECT_NAME>`, `<PROJECT_KEY>`, `<TRACKER_TYPE>`, etc.

If `CLAUDE.md` exists, scan for project metadata.

If `settings.json` exists, scan for MCP server config, hook wiring.

### Ask Only Missing Questions

For each unknown value, ask using AskUserQuestion:

1. **Project Identity** (if not detected): name, key, description
2. **Tech Stack** (if not detected): frontend/backend/database
3. **Task Tracker** (if not detected): JIRA/GitHub Issues/Linear
4. **Agent Selection**: which agents to add (show only those not already present)
5. **Hook Selection**: which hooks to add (show only those not already present)

### Generate Plan

Display the migration plan as branded output:

```bash
source $ECK_HOME/colors.sh

echo ""
printf '%b\n' "${ORANGE}${BOLD}Migration Plan${RESET}"
echo ""
printf '%b\n' "${CYAN}[*]${RESET} Will Add ({N} files)"
# list each file to create
printf '%b\n' "    {file_path}"
printf '%b\n' "${YELLOW}[>]${RESET} Will Merge ({N} files)"
# list each file to merge
printf '%b\n' "    {file_path}"
printf '%b\n' "${GREEN}[x]${RESET} Will Preserve ({N} files)"
# list each file to keep
printf '%b\n' "    {file_path}"
echo ""
printf '%b\n' "  ${DIM}Placeholder${RESET}      ${DIM}Value${RESET}"
printf '%b\n' "  PROJECT_NAME     {value}"
printf '%b\n' "  PROJECT_KEY      {value}"
```

**STOP:** Get explicit user approval before modifying any files.

### Outputs

- Complete project configuration (name, key, tracker, stack, hooks, agents); migration plan displayed; user approval obtained

### Exit Criteria

- All required configuration gathered; user has approved the migration plan

---

## Stage 4: Apply Infrastructure

### Inputs

- Migration plan from Stage 3 (files to add, merge, preserve)
- Project configuration from Stage 3 interview
- `$ECK_HOME/` template source
- `$ECK_HOME/registry.yaml` (for state transition)

### Activities

### Backup First

```bash
BACKUP_DIR="{TARGET_PATH}/.claude-backup-$(date +%Y%m%d-%H%M%S)"
if [ -d "{TARGET_PATH}/.claude" ]; then
  cp -r {TARGET_PATH}/.claude "$BACKUP_DIR"
fi
```

### Apply Rules

| Existing File?              | Action                                    |
| --------------------------- | ----------------------------------------- |
| No                          | Copy from catalog, replace placeholders   |
| Yes, unchanged from catalog | Skip (already synced)                     |
| Yes, modified               | Preserve existing file (do NOT overwrite) |

### Merge Strategy for Key Files

**settings.json** (if exists):

- Parse both as JSON
- Union hook arrays (add new hooks, keep existing)
- Preserve custom permissions and MCP config
- Add missing catalog entries

**project-constants.md** (if exists):

- Add missing sections from catalog template
- Preserve all existing values
- Never overwrite filled-in values with placeholders

**CLAUDE.md** (if exists):

- Section merge: add new sections from template
- Preserve all project-specific content

### For Each New File

1. Apply using the template engine (copy + resolve in one step):
   ```bash
   node "$(npm root -g)/@evolvconsulting/evolv-coder-kit/bin/template-cli.js" \
     apply <template-source> <target-path> \
     --values {TARGET_PATH}/.claude/project-constants.md
   ```
2. Set permissions (executable for hooks)
3. After all files applied, verify no unresolved placeholders:
   ```bash
   node "$(npm root -g)/@evolvconsulting/evolv-coder-kit/bin/template-cli.js" \
     verify {TARGET_PATH}/.claude --format text
   ```

### Generate Deployed Catalog

Write a complete `project-catalog.yaml` at `<TARGET_PATH>/.claude/project-catalog.yaml` listing all deployed components:

1. Read the canonical catalog from `$ECK_HOME/global-catalog.yaml`
2. For each component that was deployed (existing + newly added):
   - Copy the entry from the canonical catalog
   - Set `status: synced` for new files, `status: modified` for preserved existing files
   - Compute the deployed checksum
3. Set metadata:
   - `deployed_at`: current date
   - `deployed_by`: `/eck:migrate-project`
   - `project_name`: `<PROJECT_NAME>`
   - `project_key`: `<PROJECT_KEY>`
4. Initialize `sync_history` with a migration entry:

```yaml
sync_history:
  - date: "{DATE}"
    action: "migrate"
    performed_by: "/eck:migrate-project"
    summary: "Migration: {N} added, {N} merged, {N} preserved"
```

### Update Registry State

**Reference:** `ops:registry-update` primitive for the canonical read-modify-write procedure.

1. Read `$ECK_HOME/registry.yaml`. If it does not exist, log a warning and skip registry update.
2. If the project has an existing entry with `state: "discovered"`:
   - Transition to `state: "managed"`
   - Set `audit_status: "pending"`
   - Update `deployment` metadata with migration details
   - Update `project_name` and `project_path` fields
3. If the project has no entry, add one with all required fields per `ops:registry-update` field tiers:
   - **Tier 1 (Identity):** `project_name`, `project_path`, `project_key`, `state: "managed"`, `audit_status: "pending"`, `last_modified_at: "<DATE>"`
   - **Tier 2 (Configuration):** `tracker_type`, `doc_platform`, `divergence_policy: "standard"`, `dev_rigor`, `project_type`, `learning_autonomy` (from interview or auto-detected values)
   - **Tier 2 (Deployment):** `deployment` block with `initial_deploy_date`, `deployed_by: "/eck:migrate-project"`, `template_version`, `has_deployed_catalog`, `start_project_completed: false`
   - **Tier 3 (Operational):** `enrichment: { tech_stack: null, last_enriched: null }`, `last_audit` block (all null), `pull_candidates: []`, `sync_history: []`
   - Check for KEY_CONFLICT and PATH_CONFLICT per `ops:registry-update` primitive Step 1.5
4. Append a `sync_history` entry:

```yaml
- date: "{DATE}"
  action: "migrate"
  performed_by: "/eck:migrate-project"
  summary: "Migrated to managed: {N} added, {N} merged, {N} preserved"
```

5. Set `last_modified_at` to current ISO-8601 date.
6. Recompute `project_summary` per the `ops:registry-update` primitive.
7. Copy `registry.yaml` to `registry.yaml.bak`.
8. Atomic write: write to `registry.yaml.tmp`, then rename to `registry.yaml`.

### Outputs

- Infrastructure applied (new files added, existing files merged/preserved); `project-catalog.yaml` generated; registry entry created or updated

### Exit Criteria

- All files applied without error; catalog written; registry updated atomically

---

## Stage 5: Summary

### Inputs

- Applied/merged/preserved file counts from Stage 4
- Backup directory path from Stage 4
- Project name and path

### Activities

Display as a summary box with status symbols:

```bash
source $ECK_HOME/colors.sh

echo ""
printf '%b\n' "${ORANGE}${BOLD}Migration Complete${RESET}"
echo ""
printf '%b\n' "Project: {PROJECT_NAME}"
printf '%b\n' "Added: {N} files"
printf '%b\n' "Merged: {N} files"
printf '%b\n' "Preserved: {N} files"
printf '%b\n' "Skipped: {N} files"
printf '%b\n' "Backup: {BACKUP_DIR}"
printf '%b\n' "Catalog: {TARGET_PATH}/.claude/project-catalog.yaml"
echo ""
printf '%b\n' "${GREEN}[x]${RESET} Migration complete"
printf '%b\n' "${DIM}    Rollback: rm -rf {TARGET_PATH}/.claude${RESET}"
printf '%b\n' "${DIM}             cp -r {BACKUP_DIR} {TARGET_PATH}/.claude${RESET}"
echo ""
printf '%b\n' "${YELLOW}[>]${RESET} Next steps:"
printf '%b\n' "    1. Review changes: git diff"
printf '%b\n' "    2. Run /eck:audit-unmanaged-project to verify"
printf '%b\n' "    3. Run /eck:pull-from-global-catalog for updates"
```

### Outputs

- Completion summary displayed with file counts, backup path, and next steps

### Exit Criteria

- Summary displayed; statusline reset; skill complete

---

## Non-Destructive Guarantees

1. **Always backup** before any modifications
2. **Never overwrite** existing project files without merge strategy
3. **Preserve all custom content** — only add missing pieces
4. **Interview only for unknowns** — auto-detect as much as possible
5. **User approval required** before any file changes

---

## Error Handling

### Backup Failed

```bash
printf '%b\n' "${RED}[!]${RESET} Cannot create backup at {BACKUP_DIR}"
printf '%b\n' "    ${DIM}Check disk space and permissions.${RESET}"
printf '%b\n' "    ${DIM}No changes will be applied without a successful backup.${RESET}"
```

### Placeholder Replacement Incomplete

```bash
printf '%b\n' "${YELLOW}[>]${RESET} {N} unreplaced placeholders found in:"
printf '%b\n' "    ${DIM}{list of files}${RESET}"
printf '%b\n' "    ${DIM}Check project-constants.md for missing values.${RESET}"
```

---

## Related Documents

- [/eck:new-project skill](../new-project/SKILL.md) - Full interview-driven scaffolding for new projects
- [/eck:audit-unmanaged-project skill](../audit-unmanaged-project/SKILL.md) - Health check for managed projects
- [/eck:pull-from-global-catalog skill](../pull-from-global-catalog/SKILL.md) - Pull catalog updates into managed project
