---
name: eck:pull-from-user-catalog
version: "0.7.4"
description: Pull user-harvested infrastructure improvements from user-catalog.yaml into a managed project with approval flow and sync tracking.
disable-model-invocation: false
---

# Pull From User Catalog

Pull user-harvested improvements from `$ECK_HOME/user-catalog.yaml` into a managed project. The user catalog contains components previously harvested from other projects via `/eck:push-to-user-catalog`.

---

## 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/8) |
| 2     | Stage 2: Change Set     | Computing change set    | ChangeSet (2/8) |
| 3     | Stage 3: Approval       | Getting approval        | Approval (3/8)  |
| 4     | Stage 4: Backup         | Creating backup         | Backup (4/8)    |
| 5     | Stage 5: Apply          | Applying changes        | Apply (5/8)     |
| 6     | Stage 6: Update Catalog | Updating catalog        | Catalog (6/8)   |
| 7     | Stage 7: Registry       | Updating registry       | Registry (7/8)  |
| 8     | Stage 8: Summary        | Generating summary      | Summary (8/8)   |

## Usage

```bash
/eck:pull-from-user-catalog                    # Pull to current directory
/eck:pull-from-user-catalog <project-path>     # Pull to specific project
```

---

## Stage 1: Pre-Flight

### Inputs

- `$ARGUMENTS` — optional target project path (defaults to current directory)
- `$ECK_HOME/user-catalog.yaml`
- `<TARGET_PATH>/.claude/project-catalog.yaml`
- `$ECK_HOME/registry.yaml`

### Activities

### Requirements

- Write access to target project directory
- Read access to user catalog: `$ECK_HOME/user-catalog.yaml`
- Read access to registry: `$ECK_HOME/registry.yaml`

### Verification

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

# Check target project has project-catalog.yaml
ls {TARGET_PATH}/.claude/project-catalog.yaml

# Check registry
ls $ECK_HOME/registry.yaml
```

**If `user-catalog.yaml` not found:**

```bash
printf '%b\n' "${RED}[!]${RESET} No user catalog found at"
printf '%b\n' "    $ECK_HOME/user-catalog.yaml"
printf '%b\n' ""
printf '%b\n' "    ${DIM}The user catalog is populated by${RESET}"
printf '%b\n' "    ${DIM}/eck:push-to-user-catalog, which harvests${RESET}"
printf '%b\n' "    ${DIM}improvements from managed projects.${RESET}"
printf '%b\n' ""
printf '%b\n' "    ${DIM}Alternatives:${RESET}"
printf '%b\n' "    ${DIM}  /eck:pull-from-global-catalog${RESET}"
printf '%b\n' "    ${DIM}  /eck:push-to-user-catalog${RESET}"
```

**If project not managed:** Suggest running `/eck:migrate-project` or `/eck:new-project` first.

### Outputs

- Resolved target project path; user catalog, project catalog, and registry confirmed accessible

### Exit Criteria

- User catalog, project catalog, and target directory found; prerequisites satisfied

---

## Stage 2: Build Change Set

### Inputs

- User catalog from Stage 1 (`$ECK_HOME/user-catalog.yaml`)
- Project catalog from Stage 1 (`<TARGET_PATH>/.claude/project-catalog.yaml`)
- Registry from Stage 1 (`$ECK_HOME/registry.yaml`)

### Activities

### 2.1: Load Catalogs

Read and parse:

1. `$ECK_HOME/user-catalog.yaml` — harvested components
2. `<TARGET_PATH>/.claude/project-catalog.yaml` — current project state
3. `$ECK_HOME/registry.yaml` — sync history

### 2.2: Compute Differences

For each entry in `user-catalog.yaml`:

1. Check if component exists in target project
2. Compare checksums
3. Classify:
   - **new**: Component not in project at all
   - **updated**: Component exists but user-catalog checksum is newer
   - **same**: Checksums match (skip)
   - **conflict**: Both project and user-catalog have changes vs original

### 2.3: Filter

Exclude items where `source_project` matches the current target project (don't pull your own harvested items back).

Present change set with branded output:

```bash
source $ECK_HOME/colors.sh

echo ""
printf '%b\n' "${ORANGE}${BOLD}Pull Candidates${RESET}"
echo ""
printf '%b\n' "${CYAN}[*]${RESET} New components ({N}):"
printf '%b\n' "    {type}/{name}  ${DIM}from: {source_project}${RESET}"
printf '%b\n' "${YELLOW}[>]${RESET} Updated components ({N}):"
printf '%b\n' "    {type}/{name}  ${DIM}from: {source_project}${RESET}"
printf '%b\n' "    ${DIM}Diff: {summary}${RESET}"
printf '%b\n' "${RED}[!]${RESET} Conflicts ({N}):"
printf '%b\n' "    {type}/{name}  ${DIM}both project and catalog diverged${RESET}"
printf '%b\n' "${DIM}[-]${RESET} Skipped ({N} -- already in sync)"
```

### Outputs

- Classified change set: new, updated, conflict, and skipped components

### Exit Criteria

- Change set computed; counts displayed to user

---

## Stage 3: Approval Flow

### Inputs

- Change set from Stage 2 (new, updated, and conflict components)

### Activities

Present each category for approval using AskUserQuestion:

1. **New components**: "Apply {N} new components from user catalog?"
2. **Updated components**: Show diffs, ask for confirmation per component
3. **Conflicts**: Show both versions, ask user to choose (keep local / take catalog / skip)

### Outputs

- User-approved list of components to apply; conflict resolutions recorded

### Exit Criteria

- User has responded to all categories; at least one component approved or skill exits cleanly

---

## Stage 4: Backup

### Inputs

- List of files to be modified (from Stage 3 approval)
- Target project path

### Activities

Before applying changes, back up files that will be modified:

```bash
mkdir -p {TARGET_PATH}/.claude/backups/{TIMESTAMP}
cp {file} {TARGET_PATH}/.claude/backups/{TIMESTAMP}/
```

### Outputs

- Backup created at `<TARGET_PATH>/.claude/backups/<TIMESTAMP>/`

### Exit Criteria

- All files to be modified are backed up

---

## Stage 5: Apply Changes

### Inputs

- Approved component list from Stage 3
- Backup path from Stage 4
- User catalog source files

### Activities

For each approved component:

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. Verify checksum after write
3. After all components applied, verify no unresolved placeholders:
   ```bash
   node "$(npm root -g)/@evolvconsulting/evolv-coder-kit/bin/template-cli.js" \
     verify {TARGET_PATH}/.claude --format text
   ```

### Outputs

- Approved components written to target project; checksums verified

### Exit Criteria

- All approved components applied without checksum errors

---

## Stage 6: Update project-catalog.yaml

### Inputs

- Applied component list from Stage 5 (with new checksums)
- Current `<TARGET_PATH>/.claude/project-catalog.yaml`

### Activities

Update `<TARGET_PATH>/.claude/project-catalog.yaml`:

- Add new entries for newly pulled components
- Update checksums for updated components
- Add `pulled_from: user-catalog` attribution
- Add `pull_date: {timestamp}`

### Outputs

- `project-catalog.yaml` updated with new entries, checksums, and attribution

### Exit Criteria

- `project-catalog.yaml` written successfully

---

## Stage 7: Update Registry

### Inputs

- Applied component summary from Stage 5 (counts: pulled, skipped, conflicts)
- `$ECK_HOME/registry.yaml` (if exists)

### Activities

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

If registry does not exist, log warning and skip this step.

Set `last_modified_at` to current ISO-8601 date.

Append to the project's `sync_history` in `$ECK_HOME/registry.yaml`:

```yaml
- date: "{DATE}"
  action: "pull-from-user-catalog"
  performed_by: "/eck:pull-from-user-catalog"
  summary: "{N} pulled, {N} skipped, {N} conflicts"
```

Recompute `project_summary` per the `ops:registry-update` primitive.

Use atomic write: write to `registry.yaml.tmp`, then rename to `registry.yaml`.

### Outputs

- `registry.yaml` updated with sync history entry and `last_modified_at`

### Exit Criteria

- Registry written atomically (or skipped with warning if registry not found)

---

## Stage 8: Summary

### Inputs

- Applied counts from Stage 5
- Catalog and registry update status from Stages 6-7

### Activities

Display as a summary box with status symbols:

```bash
source $ECK_HOME/colors.sh

echo ""
printf '%b\n' "${ORANGE}${BOLD}Pull Complete${RESET}"
echo ""
printf '%b\n' "Applied: {N} components"
printf '%b\n' "  New: {N}"
printf '%b\n' "  Updated: {N}"
printf '%b\n' "Skipped: {N} (already in sync)"
printf '%b\n' "Conflicts: {N} resolved"
printf '%b\n' "Backup: .claude/backups/{TIMESTAMP}/"
echo ""
printf '%b\n' "${GREEN}[x]${RESET} Pull from user catalog complete"
printf '%b\n' "${GREEN}[x]${RESET} Updated project-catalog.yaml"
printf '%b\n' "${GREEN}[x]${RESET} Updated registry.yaml"
```

### Outputs

- Completion summary displayed to user

### Exit Criteria

- Summary displayed; statusline reset; skill complete

---

## Error Recovery

Use branded error format for all errors:

```bash
# User catalog not found
printf '%b\n' "${RED}[!]${RESET} User catalog not found."
printf '%b\n' "    ${DIM}Run /eck:push-to-user-catalog first.${RESET}"

# Project not managed
printf '%b\n' "${RED}[!]${RESET} Project is not managed."
printf '%b\n' "    ${DIM}Run /eck:migrate-project first.${RESET}"

# Write failure
printf '%b\n' "${RED}[!]${RESET} Write failure during apply."
printf '%b\n' "    ${DIM}Restoring from backup...${RESET}"

# Checksum mismatch
printf '%b\n' "${RED}[!]${RESET} Checksum mismatch after write."
printf '%b\n' "    ${DIM}Re-attempting write, verify disk.${RESET}"
```

---

## Related Documents

- [Pull From Global Catalog](../pull-from-global-catalog/SKILL.md)
- [Push To User Catalog](../push-to-user-catalog/SKILL.md)
- [Audit Current Project](../audit-current-project/SKILL.md)
- [Migrate Project](../migrate-project/SKILL.md)
- [Global Catalog]($ECK_HOME/global-catalog.yaml)
