---
name: eck:pull-from-global-catalog
version: "0.7.4"
description: Apply template and agent updates from the global catalog to a managed project with catalog-driven reconciliation, smart merging, and rollback support. Reads ONLY from global-catalog.yaml.
disable-model-invocation: false
---

# Pull From Global Catalog Workflow

Pull template and agent updates from the global catalog (`$ECK_HOME/global-catalog.yaml`) into a managed project. Reads ONLY from `global-catalog.yaml` — the canonical source of truth for all managed templates and agents. Uses placeholder-aware diffing (resolves placeholders before checksum comparison), diff classification (placeholder-only / formatting / content), recursive file discovery, and full sync history tracking. Includes agent selection UI for pulling specific agents.

---

## 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/9) |
| 2     | Stage 2: Change Set      | Computing change set    | ChangeSet (2/9) |
| 3     | Stage 3: Agent Selection | Selecting agents        | AgentSel (3/9)  |
| 4     | Stage 4: Approval        | Getting approval        | Approval (4/9)  |
| 5     | Stage 5: Backup          | Creating backup         | Backup (5/9)    |
| 6     | Stage 6: Apply           | Applying changes        | Apply (6/9)     |
| 7     | Stage 7: Placeholders    | Replacing placeholders  | Placehld (7/9)  |
| 8     | Stage 8: Update Catalog  | Updating catalog        | Catalog (8/9)   |
| 9     | Stage 9: Verify          | Verifying installation  | Verify (9/9)    |

## Usage

```bash
/eck:pull-from-global-catalog                          # Pull to current directory
/eck:pull-from-global-catalog <project-path>           # Pull to specific project
/eck:pull-from-global-catalog --agents                 # Agent selection UI only
/eck:pull-from-global-catalog --agents --all           # Pull all agents
/eck:pull-from-global-catalog --agents --domain backend  # Pull agents by domain
```

---

## Stage 1: Pre-Flight

### Inputs

- Target project path from `$ARGUMENTS` (defaults to current directory)
- `$ECK_HOME/global-catalog.yaml`
- `$ECK_HOME/registry.yaml` (optional)
- `.claude/project-catalog.yaml` (if exists)

### 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`

### Registry Context

Read the target project's entry from `$ECK_HOME/registry.yaml` (if registry exists):

1. **Divergence policy check:**
   - If `divergence_policy: intentional-divergence`, warn user:
     ```bash
     printf '%b\n' "${YELLOW}[>]${RESET} Divergence policy: intentional-divergence"
     printf '%b\n' "    ${DIM}This project intentionally deviates from templates.${RESET}"
     printf '%b\n' "    ${DIM}Review each category individually.${RESET}"
     ```
   - Adjust expectations: do NOT flag intentionally-replaced components as gaps

2. **Show project context:**

   ```bash
   echo ""
   printf '%b\n' "${ORANGE}${BOLD}Project Context${RESET}"
   echo ""
   printf '%b\n' "Project: {PROJECT_NAME}"
   printf '%b\n' "Last Audit: {date} (health: {score}%)"
   printf '%b\n' "Template: v{template_version_deployed}"
   printf '%b\n' "Synced: {N}"
   printf '%b\n' "Modified: {N}"
   printf '%b\n' "Outdated: {N}"
   printf '%b\n' "Missing: {N}"
   printf '%b\n' "Pull Pending: {N}"
   echo ""
   ```

3. **Check for pending pulls:**
   - If the project has items in `$ECK_HOME/audits/pull-candidates.md` with status `PENDING`, warn:
     ```bash
     printf '%b\n' "${YELLOW}[>]${RESET} {N} pull candidates still PENDING"
     printf '%b\n' "    ${DIM}Consider running /eck:push-to-user-catalog first.${RESET}"
     ```

**If registry doesn't exist:** Skip registry context with note. Proceed normally.

### Source Path Resolution

The template source is always the installed global catalog at `$ECK_HOME/`. This ensures the pull tests the full E2E path (scaffold → install → pull).

```bash
TEMPLATE_SOURCE="$HOME/.claude/evolv-coder-kit"
printf '%b\n' "${CYAN}[*]${RESET} Source: $TEMPLATE_SOURCE"
```

Store `TEMPLATE_SOURCE` for use in all subsequent stages.

### Audit Check

**If target has a recent catalog** (`.claude/project-catalog.yaml` with `last_audit` within 24 hours):

- Use existing catalog data to build change set (skip full audit)
- Inform user: "Using recent audit from {date}. Run /eck:audit-unmanaged-project first for a fresh scan."
- Check for corresponding audit report in `$ECK_HOME/audits/` for additional context

**If target has no catalog or stale catalog:**

- **MUST** run the full `/eck:audit-unmanaged-project` workflow internally (Stages 1-6). Do NOT skip the audit or proceed with stale data
- This generates the classification data needed for the change set

**If target has no `.claude/` directory:**

```bash
printf '%b\n' "${RED}[!]${RESET} No .claude/ directory found at {TARGET_PATH}"
printf '%b\n' "    ${DIM}Use /eck:new-project to bootstrap, or${RESET}"
printf '%b\n' "    ${DIM}/eck:migrate-project to onboard.${RESET}"
```

### Outputs

- Registry context loaded; `TEMPLATE_SOURCE` resolved; audit data available

### Exit Criteria

- Prerequisites verified; audit data present (fresh or recently cached)

---

## Stage 2: Build Change Set

### Inputs

- Audit classification data from Stage 1 (or internal audit run)
- Placeholder map from `project-constants.md`
- `$ECK_HOME/global-catalog.yaml`

### Activities

From the audit results, build a categorized change set:

### Placeholder-Aware Comparison via Template Engine

Use the template engine to build a placeholder-aware change set:

```bash
node "$(npm root -g)/@evolvconsulting/evolv-coder-kit/bin/template-cli.js" \
  changeset $ECK_HOME/.claude {TARGET_PATH}/.claude \
  --values {TARGET_PATH}/.claude/project-constants.md \
  --format json
```

The changeset returns per-file classification (`identical`, `placeholder-only`, `formatting`, `content`) and `unresolvedTokens` for each entry. Files with `placeholder-only` classification are correctly installed and should not appear as diffs.

**Unresolvable placeholders:** Entries with non-empty `unresolvedTokens` should be flagged separately:

```bash
printf '%b\n' "${YELLOW}[>]${RESET} {N} files skipped — unresolvable placeholders"
printf '%b\n' "    ${DIM}{file}: {TOKEN_1}, {TOKEN_2}${RESET}"
printf '%b\n' "    ${DIM}Add values to project-constants.md to include${RESET}"
```

### Recursive File Discovery

When scanning for template files, use recursive discovery for nested directory structures:

- **Primitives:** `find <TEMPLATE_SOURCE>/primitives/ -name "*.md" -not -name "README.md"` — primitives are nested (e.g., `core/ops/*.md`, `core/agent/*.md`, `tracker/github/*.md`)
- **Skills:** `find <TEMPLATE_SOURCE>/skills/ -name "SKILL.md"` — each skill is in its own directory
- **Agents:** `find <TEMPLATE_SOURCE>/agents/ -name "*.md" -not -name "README.md"` — flat structure
- **Context:** `find <TEMPLATE_SOURCE>/context/ -name "*.md"` — may have subdirectories

Do NOT use flat globs (e.g., `primitives/core/*.md`) that miss subdirectories.

### Change Actions

| Action        | Source  | Target         | Condition                                                                |
| ------------- | ------- | -------------- | ------------------------------------------------------------------------ |
| **ADD**       | Catalog | Target project | Item is `missing` and `required: true` (or conditionally applicable)     |
| **UPDATE**    | Catalog | Target project | Item is `outdated` (catalog version > deployed version)                  |
| **REPLACE**   | Catalog | Target project | Item is `modified` with `modification_type: regression`                  |
| **DEPRECATE** | Catalog | Target project | Item is `deprecated` in catalog but still active in project              |
| **SKIP**      | —       | —              | Item is `synced`, `custom`, or `modified (improvement/project-specific)` |

### Change Catalog Format

Display the change set with a summary box and categorized status symbols.

**Change set header:**

```bash
echo ""
printf '%b\n' "${ORANGE}${BOLD}Change Set: {PROJECT_NAME}${RESET}"
echo ""
printf '%b\n' "ADD: {N} new components"
printf '%b\n' "UPDATE: {N} outdated components"
printf '%b\n' "REPLACE: {N} regressed components"
printf '%b\n' "DEPRECATE: {N} old components"
printf '%b\n' "SKIP: {N} unchanged or custom"
echo ""
```

**ADD section:**

```bash
printf '%b\n' "${ORANGE}${BOLD}Add: New Components${RESET}"
echo ""
printf '%b\n' "${GREEN}[x]${RESET} {file} — {category} v{version}"
printf '%b\n' "    ${DIM}{description}${RESET}"
```

**UPDATE section:**

```bash
printf '%b\n' "${ORANGE}${BOLD}Update: Outdated Components${RESET}"
echo ""
printf '%b\n' "${CYAN}[*]${RESET} {file} — v{old} -> v{new}"
printf '%b\n' "    ${DIM}{brief diff summary}${RESET}"
```

**REPLACE section:**

```bash
printf '%b\n' "${ORANGE}${BOLD}Replace: Regressed Components${RESET}"
echo ""
printf '%b\n' "${RED}[!]${RESET} {file} — {what regressed}"
printf '%b\n' "    ${DIM}Restoring template v{version}${RESET}"
```

**DEPRECATE section:**

```bash
printf '%b\n' "${ORANGE}${BOLD}Deprecate${RESET}"
echo ""
printf '%b\n' "${YELLOW}[>]${RESET} {file} — superseded by {replacement}"
```

After listing all deprecated items, display cleanup guidance:

```bash
echo ""
printf '%b\n' "${CYAN}[*]${RESET} To remove deprecated items:"
printf '%b\n' "    ${DIM}/eck:clean-deprecated${RESET}"
printf '%b\n' "    ${DIM}/eck:clean-deprecated --dry-run  (preview)${RESET}"
```

**SKIP section:**

```bash
printf '%b\n' "${ORANGE}${BOLD}Skip: No Action Needed${RESET}"
echo ""
printf '%b\n' "${DIM}[-]${RESET} {file} — {status}: {reason}"
```

Only display sections that have items. Omit empty sections.

### Outputs

- Categorized change set (ADD/UPDATE/REPLACE/DEPRECATE/SKIP) with diff classifications

### Exit Criteria

- Change set built and displayed; ready for user approval in Stage 4

### Diff Classification

Classify each UPDATE/REPLACE item to help operators prioritize review:

| Category             | Criteria                                                                 | Display              | Approval            |
| -------------------- | ------------------------------------------------------------------------ | -------------------- | ------------------- |
| **placeholder-only** | Raw template differs from deployed, but post-replacement checksums match | `${DIM}[P]${RESET}`  | Auto-apply          |
| **formatting**       | Differences are whitespace, table alignment, or trailing newlines only   | `${DIM}[F]${RESET}`  | Batch-approve       |
| **content**          | Actual instruction, logic, or structural changes                         | `${CYAN}[C]${RESET}` | Review individually |

Display classification inline with each item:

```bash
printf '%b\n' "${CYAN}[*]${RESET} ${DIM}[P]${RESET} skill/dev-pr/SKILL.md — placeholder-only"
printf '%b\n' "${CYAN}[*]${RESET} ${DIM}[F]${RESET} primitives/git/commit.md — formatting"
printf '%b\n' "${CYAN}[*]${RESET} ${CYAN}[C]${RESET} agents/backend-developer.md — v0.4.0 -> v0.5.0"
```

In the change set header, add classification counts:

```bash
printf '%b\n' "  ${DIM}Breakdown: {N} placeholder-only, {N} formatting, {N} content${RESET}"
```

### Overlap Detection

Check for conflicts where a catalog template now includes something that was previously custom in the project:

- Compare custom item names/paths against new catalog items
- If overlap detected, add to a special "CONFLICT" section with options:
  - **Replace custom with standard** — adopt the catalog version
  - **Keep custom** — preserve project version, mark as `protected`
  - **Merge** — combine both (requires manual review)

---

## Stage 3: Agent Selection (--agents mode or included in full pull)

### Inputs

- `$ECK_HOME/.claude/agents/` directory
- `.claude/agents/` in target project

### Activities

### Enumerate Catalog Agents

Read all `.md` files from `$ECK_HOME/.claude/agents/` (excluding README.md).

For each agent, extract from YAML frontmatter:

- `name` — agent identifier
- `description` — what the agent does
- `model` — model tier (opus/sonnet/haiku)

### Categorize by Domain

| Domain        | Agents                                                                                      |
| ------------- | ------------------------------------------------------------------------------------------- |
| Backend       | backend-architect, backend-developer, backend-qa, backend-designer                          |
| Frontend      | frontend-architect, frontend-designer, frontend-developer, frontend-qa                      |
| Cross-cutting | database-specialist, devops-engineer, security-specialist, integration-qa, technical-writer |
| Utility       | code-simplifier                                                                             |

### Check Existing Project Agents

Scan `.claude/agents/` to identify:

- **Already present** — agent file exists in project
- **Modified** — exists but differs from catalog (checksum comparison)
- **Missing** — not present in project

### Present Agent Inventory

```bash
echo ""
printf '%b\n' "${ORANGE}${BOLD}Available Agents${RESET}"
echo ""
printf '%b\n' "  ${DIM}#${RESET}  Agent                    Domain        Status"
printf '%b\n' "  ${DIM}──${RESET} ───────────────────────── ──────────── ─────────────"
printf '%b\n' "  1  backend-architect        Backend      ${RED}[!]${RESET} Missing"
printf '%b\n' "  2  backend-developer        Backend      ${YELLOW}[>]${RESET} Modified"
printf '%b\n' "  3  security-specialist      Cross-cut    ${GREEN}[x]${RESET} Synced"
```

Use `[!]` red for Missing, `[>]` yellow for Modified, `[x]` green for Synced.

Prompt: `Select agents to pull: (all / none / 1,3,5 / domain:backend / missing-only)`

### Conflict Handling

For agents marked as Modified:

```bash
printf '%b\n' "${YELLOW}[>]${RESET} Agent 'backend-developer' differs from catalog"
printf '%b\n' "    ${DIM}1. Overwrite with catalog version${RESET}"
printf '%b\n' "    ${DIM}2. Keep project version${RESET}"
printf '%b\n' "    ${DIM}3. Show diff${RESET}"
```

### Outputs

- Agent inventory with status (missing/modified/synced) and user selection

### Exit Criteria

- User has selected which agents to pull (or stage skipped if `--agents` not involved)

---

## Stage 4: Per-Category Approval

### Inputs

- Change set from Stage 2
- Agent selections from Stage 3

### Activities

Present the change set for approval using AskUserQuestion, one category at a time.

### Approval Flow

For each category with changes (root_files, config, agents, skills, hooks, primitives, context):

```
### Category: {category_name}

| Action | Count |
|--------|-------|
| ADD | {N} |
| UPDATE | {N} |
| REPLACE | {N} |
| DEPRECATE | {N} |

{Table of individual items}

Apply {category_name} changes? (Y/n/review)
```

- **Y** — Apply all changes in this category
- **n** — Skip this category entirely
- **review** — Show detailed diffs for each item, then ask per-item

**STOP:** Do not proceed to Stage 5 until all categories have been presented and user has responded.

### Conflict Resolution

For any overlap/conflict items detected in Stage 2:

```
### Conflict: {file_name}

Your project has a custom version of this file.
The catalog template now includes a standard version.

Custom version summary: {brief description of custom content}
Standard version summary: {brief description of template content}

Choose:
1. Replace with standard (your customizations will be backed up)
2. Keep your custom version (mark as protected)
3. Show diff for manual merge decision
```

### Outputs

- Per-category approval decisions (apply/skip/review-per-item)

### Exit Criteria

- All categories presented and user has responded; no changes applied yet

---

## Stage 5: Backup

### Inputs

- Approved change set from Stage 4
- Target project `.claude/` directory and root files to be modified

### Activities

Before any modifications:

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

# Also backup root files being modified
for f in CLAUDE.md development-workflow.md workflow-quick-reference.md workflow-diagrams.md project-constitution.md .mcp.json; do
  if [ -f "{TARGET_PATH}/$f" ]; then
    cp "{TARGET_PATH}/$f" "$BACKUP_DIR/"
  fi
done

echo "Backup created at: $BACKUP_DIR"
```

**If backup fails:** STOP immediately. Do not apply any changes.

### Outputs

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

### Exit Criteria

- Backup created successfully; or skill stops if backup fails

---

## Stage 6: Apply Changes

### Inputs

- Approved change set from Stage 4
- Backup from Stage 5
- Template files from `$ECK_HOME/`
- Placeholder map from Stage 2

### Activities

### Smart Merge Strategies

Apply approved changes using category-specific merge strategies:

#### Agents

- **ADD:** Copy template file, replace placeholders
- **UPDATE:** Replace body content, preserve custom `tools:` entries in YAML frontmatter
- **Strategy:** Read existing frontmatter, extract custom tool entries not in template, merge into updated file

#### Config — settings.json

- **Strategy:** Structural merge
  - Parse both existing and template as JSON
  - Union hook arrays (add new hooks, preserve existing custom hooks)
  - Preserve custom entries not in template
  - Do NOT remove hooks the user added manually
- **Never overwrite:** Custom MCP configurations, user-added permissions

#### Config — project-constants.md

- **Strategy:** Section-level merge via template-cli

  ```bash
  node "$TEMPLATE_CLI" merge-sections \
    <template-constants> <deployed-constants> \
    --strategy constants \
    --output <deployed-constants>
  ```

  - Adds new sections from template that don't exist in project
  - Adds new rows to existing table sections
  - Preserves ALL existing values — never overwrites a filled-in value with a placeholder

#### Skills

- **ADD:** Copy entire skill directory, replace placeholders
- **UPDATE:** Replace skill body content, preserve any custom stages the user added
- **Strategy:** Compare stage headers; if project has stages not in template, append them

#### Hooks

- **ADD:** Copy hook file, make executable (`chmod +x`)
- **UPDATE:** Replace entire file (hooks should not have project-specific customizations)
- **Wire:** After adding new hooks, update `settings.json` to include hook event bindings

#### Primitives

- **ADD:** Copy primitive file, replace placeholders
- **UPDATE:** Replace entire file (primitives are atomic and shouldn't diverge)

#### Context Standards

- **ADD:** Copy file
- **UPDATE:** Replace entire file (standards are sourced from catalog)

#### Root Files — CLAUDE.md, project-constitution.md

- **Strategy:** Section-level merge via template-cli

  ```bash
  node "$TEMPLATE_CLI" merge-sections \
    <template-file> <deployed-file> \
    --strategy markdown \
    --values {TARGET_PATH}/.claude/project-constants.md \
    --output <deployed-file>
  ```

  - Adds new sections from template, preserves user-customized sections
  - Uses template section order, appends user-added sections at end
  - Updates version/date in preamble from template

- **Other root files:** Replace with template version (generic workflow docs)

### For Each Applied File:

1. Apply using the template engine (copy + resolve in one step):
   ```bash
   TEMPLATE_CLI="$(npm root -g)/@evolvconsulting/evolv-coder-kit/bin/template-cli.js"
   node "$TEMPLATE_CLI" apply <template-source> <target-path> \
     --values {TARGET_PATH}/.claude/project-constants.md
   ```
2. For root files (CLAUDE.md, project-constants.md, project-constitution.md), use `merge-sections` instead of `apply`
3. Set appropriate permissions (executable for hooks)

### Outputs

- All approved files added, updated, or replaced in target project

### Exit Criteria

- All approved changes applied with correct permissions

---

## Stage 7: Verify Placeholders

### Inputs

- New and updated files from Stage 6

### Activities

After all files are copied/merged, verify no unresolved placeholders remain:

```bash
node "$(npm root -g)/@evolvconsulting/evolv-coder-kit/bin/template-cli.js" \
  verify {TARGET_PATH}/.claude --format text
```

The verify command excludes `project-constants.md` and `project-catalog.yaml` by default (they legitimately contain placeholder tokens).

If unresolved tokens are found (exit code 2), report them to the user with instructions to add values to `project-constants.md`.

### Outputs

- Verification that all placeholder tokens are resolved in new/updated files

### Exit Criteria

- No unreplaced `<PLACEHOLDER>` tokens remain (or user notified of any remaining)

---

## Stage 8: Update Catalog

### Inputs

- Applied changes from Stage 6
- `<TARGET_PATH>/.claude/project-catalog.yaml`

### Activities

### Update Deployed Catalog

Write or update `<TARGET_PATH>/.claude/project-catalog.yaml`:

1. Update `last_audit` timestamp
2. Update component statuses (all applied items -> `synced`)
3. Preserve custom item entries
4. Add sync_history entry:

```yaml
sync_history:
  - date: "{DATE}"
    action: "pull-from-global-catalog"
    performed_by: "/eck:pull-from-global-catalog"
    claude_code_standards_version: "{claude_code_standards_version}"
    template_version: "{template_version}"
    backup_path: "{BACKUP_DIR}"
    summary: "Added {N}, updated {N}, replaced {N}, deprecated {N}, skipped {N}"
    items_changed:
      - file: "{path}"
        action: "{ADD|UPDATE|REPLACE|DEPRECATE}"
```

### Outputs

- `project-catalog.yaml` updated with new statuses and sync history entry

### Exit Criteria

- Deployed catalog reflects all applied changes

---

## Stage 9: Verify and Summary

### Inputs

- Applied files from Stage 6
- Updated catalog from Stage 8
- `$ECK_HOME/registry.yaml` (if exists)

### Activities

### Re-Audit

Run a quick verification pass (not full audit):

1. Check all ADD items now exist
2. Check all UPDATE items have new checksums matching catalog
3. Check no unreplaced placeholders
4. Check hooks are executable
5. Check settings.json is valid JSON

### Update Registry Sync History

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

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

After a successful pull, append a `sync_history` entry to `$ECK_HOME/registry.yaml` under the target project's record:

```yaml
- date: "{ISO-8601 date}"
  action: "pull-from-global-catalog"
  performed_by: "/eck:pull-from-global-catalog"
  summary: "Pulled {N} components: {N} added, {N} updated, {N} replaced, {N} deprecated"
```

Set `last_modified_at` to current ISO-8601 date.

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

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

This provides a persistent audit trail in the global registry of all pull operations performed on each managed project.

### Summary

Display the final summary as a branded summary box with status symbols.

```bash
echo ""
printf '%b\n' "${ORANGE}${BOLD}Pull From Global Catalog Complete${RESET}"
echo ""
printf '%b\n' "Project: {PROJECT_NAME}"
echo ""
printf '%b\n' "${GREEN}[x]${RESET} Added: {N}"
printf '%b\n' "${GREEN}[x]${RESET} Updated: {N}"
printf '%b\n' "${GREEN}[x]${RESET} Replaced: {N}"
printf '%b\n' "${GREEN}[x]${RESET} Deprecated: {N}"
printf '%b\n' "${DIM}[-]${RESET} Skipped: {N}"
echo ""
printf '%b\n' "Template: v{old} -> v{new}"
printf '%b\n' "Backup: {BACKUP_DIR}"
echo ""
```

**Agents sub-section (if agents were pulled):**

```bash
printf '%b\n' "${GREEN}[x]${RESET} {name} — {Added/Updated}"
printf '%b\n' "${DIM}[-]${RESET} {name} — Skipped"
```

**Deprecated items callout (if DEPRECATE count > 0):**

```bash
printf '%b\n' "${YELLOW}[>]${RESET} {N} deprecated items flagged"
printf '%b\n' "    ${DIM}Run /eck:clean-deprecated to remove them${RESET}"
```

**Manual attention items (if any):**

```bash
printf '%b\n' "${YELLOW}[>]${RESET} {item needing manual attention}"
printf '%b\n' "    ${DIM}{description of what to do}${RESET}"
```

**Next steps:**

```bash
printf '%b\n' "${CYAN}[*]${RESET} Review changes: git diff"
printf '%b\n' "${CYAN}[*]${RESET} Test hooks: verify settings.json"
printf '%b\n' "${CYAN}[*]${RESET} Commit changes"
```

**Rollback instructions** (display only if user asks or if errors occurred):

To revert ALL changes:

```bash
rm -rf {TARGET_PATH}/.claude
cp -r {BACKUP_DIR}/.claude {TARGET_PATH}/.claude
for f in CLAUDE.md development-workflow.md workflow-quick-reference.md workflow-diagrams.md project-constitution.md .mcp.json; do
  if [ -f "{BACKUP_DIR}/$f" ]; then
    cp "{BACKUP_DIR}/$f" "{TARGET_PATH}/$f"
  fi
done
```

To revert a SPECIFIC file:

```bash
cp {BACKUP_DIR}/{relative_path} {TARGET_PATH}/{relative_path}
```

### Outputs

- Verification pass results; final summary box displayed; registry updated

### Exit Criteria

- All ADD items verified present; all UPDATE checksums match; summary displayed; statusline reset

---

## Non-Destructive Guarantees

1. **Always backup** before any modifications
2. **Never delete** custom/user-created files
3. **Never overwrite** project-specific customizations without approval
4. **Per-category approval** — user controls exactly what changes
5. **Conflict detection** — overlaps between custom and catalog are flagged
6. **Rollback instructions** provided with specific backup paths
7. **Sync history** logged in catalog for audit trail

---

## 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 backup.${RESET}"
```

### Placeholder Replacement Incomplete

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

### Settings.json Merge Failed

```bash
printf '%b\n' "${YELLOW}[>]${RESET} Could not parse settings.json for merge"
printf '%b\n' "    ${DIM}Falling back to full replacement.${RESET}"
printf '%b\n' "    ${DIM}Backup: {BACKUP_DIR}/.claude/settings.json${RESET}"
```

---

## Related Documents

- [Global Catalog]($ECK_HOME/global-catalog.yaml) - Canonical source of truth
- [/eck:audit-unmanaged-project skill](../audit-unmanaged-project/SKILL.md) - Read-only audit
- [/eck:clean-deprecated skill](../clean-deprecated/SKILL.md) - Remove deprecated items after pull
- [/eck:push-to-user-catalog skill](../push-to-user-catalog/SKILL.md) - Push improvements back to catalog
- [/eck:new-project skill](../new-project/SKILL.md) - Bootstrap new projects
- [/eck:migrate-project skill](../migrate-project/SKILL.md) - Onboard unmanaged projects
