---
name: eck:audit-unmanaged-project
version: "0.7.4"
description: Discover and register unmanaged projects by deep scanning infrastructure against canonical templates with git-aware classification and reconciliation reporting.
disable-model-invocation: false
---

# Audit Project Workflow

Perform a read-only deep scan of a target project's Claude Code infrastructure, compare against canonical templates using checksum + git history, classify every component, produce a reconciliation report, and persist the report to `$ECK_HOME/audits/` for project tracking.

---

## 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 clean bold header. 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 Blocks

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: Deep Scan       | Scanning project        | DeepScan (2/9)  |
| 3     | Stage 3: Compare         | Comparing with catalog  | Compare (3/9)   |
| 4     | Stage 4: Hook Wiring     | Wiring hooks            | HookWire (4/9)  |
| 5     | Stage 5: Standards Check | Checking standards      | StdCheck (5/9)  |
| 6     | Stage 6: Report          | Generating report       | Report (6/9)    |
| 7     | Stage 7: Persist         | Persisting results      | Persist (7/9)   |
| 8     | Stage 8: Registry        | Updating registry       | Registry (8/9)  |
| 9     | Stage 9: Update Catalog  | Updating catalog        | Catalog (9/9)   |

## Usage

```bash
/eck:audit-unmanaged-project                      # Audit current directory
/eck:audit-unmanaged-project <project-path>       # Audit specific project
/eck:audit-unmanaged-project --write-catalog     # Audit + write/update catalog in target
```

---

## Stage 1: Tool Health Check

### Inputs

- Target project path from `$ARGUMENTS` (defaults to current directory)
- `$ECK_HOME/global-catalog.yaml`
- `git` CLI availability

### Activities

**Required:**

- Read access to target project directory
- Read access to canonical templates at: `$ECK_HOME/`
- Read access to canonical catalog at: `$ECK_HOME/global-catalog.yaml`
- `git` available in both repos (for history-aware classification)

**Verification:**

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

# Check target has .claude/
ls {TARGET_PATH}/.claude/

# Check git available in both repos
git -C . log --oneline -1 2>/dev/null
git -C {TARGET_PATH} log --oneline -1 2>/dev/null
```

**If canonical catalog not found:** STOP with:

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

**If target has no `.claude/`:** Report as unmanaged project:

```bash
printf '%b\n' "${YELLOW}[>]${RESET} No .claude/ directory found — unmanaged project"
printf '%b\n' "    ${DIM}Consider running /eck:new-project to bootstrap.${RESET}"
```

**If git not available in target:** Proceed without git history — fall back to checksum-only classification:

```bash
printf '%b\n' "${YELLOW}[>]${RESET} Git history not available — checksum-only mode"
printf '%b\n' "    ${DIM}Pull candidate confidence will default to low.${RESET}"
```

### Outputs

- Verified access to target and canonical catalog; git availability flag

### Exit Criteria

- All tool health checks pass (or fallback mode established); skill can proceed

---

## Stage 2: Deep Scan

### Inputs

- Target project directory (verified in Stage 1)
- `<TARGET_PATH>/.claude/` files and root infrastructure files

### Activities

Enumerate every file in the target project's infrastructure directories.

### Scan Targets

```bash
# Root infrastructure files
ls {TARGET_PATH}/CLAUDE.md
ls {TARGET_PATH}/development-workflow.md
ls {TARGET_PATH}/workflow-quick-reference.md
ls {TARGET_PATH}/workflow-diagrams.md
ls {TARGET_PATH}/project-constitution.md
ls {TARGET_PATH}/.mcp.json

# .claude/ directory (recursive)
find {TARGET_PATH}/.claude/ -type f

# Existing catalog (if any)
ls {TARGET_PATH}/.claude/project-catalog.yaml
```

### Collect Inventory

For each file found, collect:

**Checksum data:**

1. Relative path (from project root)
2. Checksum (first 12 chars of SHA-256)
3. File size

**Git history (per file):**

```bash
# Last commit touching this file
git -C {TARGET_PATH} log --format="%h|%ai|%s" -1 -- {relative_path}

# Total commit count for this file
git -C {TARGET_PATH} log --oneline -- {relative_path} | wc -l
```

Capture per file:

- `last_commit_hash` — short hash (e.g., `a1b2c3d`)
- `last_commit_date` — ISO date (e.g., `2026-02-20`)
- `last_commit_message` — first line of commit message
- `commit_count` — total commits touching this file

### Collect Template Git History

For each corresponding template file:

```bash
git -C ~/.claude/evolv-coder-kit log --format="%h|%ai|%s" -1 -- {file}
```

This gives us the template-side `last_commit_date` for comparison.

### Load Project Constants

Parse `<TARGET_PATH>/.claude/project-constants.md` using the template engine:

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

This returns a JSON map of placeholder values needed for placeholder-aware diffing in Stage 3.

**If project-constants.md not found:** Flag as gap. Placeholder-aware diffing will be skipped; all template-sourced files will show as "modified" even if only placeholders differ.

### Outputs

- File inventory with checksums, sizes, and git history per file
- Placeholder map from `project-constants.md` (if available)

### Exit Criteria

- All infrastructure files enumerated and checksums computed

---

## Stage 3: Compare Against Canonical

### Inputs

- File inventory from Stage 2
- `$ECK_HOME/global-catalog.yaml`
- Placeholder map from Stage 2

### Activities

Load canonical catalog from `$ECK_HOME/global-catalog.yaml`.

### Placeholder-Aware Comparison via Template Engine

Use the template engine to compare the canonical catalog source against the project's deployed files:

```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 `added`, `removed`, `modified`, and `identical` arrays with per-file `classification`:

- `identical` — raw checksums match
- `placeholder-only` — resolved template checksum matches deployed (correctly installed)
- `formatting` — whitespace-only differences
- `content` — genuine content differences

### Classification Rules

Map template engine results to audit statuses:

| Status     | Condition                                                                                |
| ---------- | ---------------------------------------------------------------------------------------- |
| `synced`   | File in `identical` array, OR classification is `placeholder-only`                       |
| `modified` | Classification is `content` or `formatting`                                              |
| `outdated` | Classification is `content` AND canonical version is newer than deployed catalog version |
| `missing`  | File listed in catalog but in the `removed` array (not found in project)                 |

For items found in the project but NOT in the canonical catalog:

| Status   | Condition                                               |
| -------- | ------------------------------------------------------- |
| `custom` | File exists in project but has no canonical counterpart |

### Git-Aware Modification Sub-Classification

For `modified` items, use **both the diff content AND git history** to classify:

| Sub-type           | Determination                                     |
| ------------------ | ------------------------------------------------- |
| `improvement`      | Deliberate enhancement that benefits all projects |
| `project-specific` | Tailored to this project's unique needs           |
| `regression`       | Removes functionality or worsens patterns         |

**Git signals for classification:**

| Signal                                                      | Indicates                                               |
| ----------------------------------------------------------- | ------------------------------------------------------- |
| `commit_count > 1` on project file                          | Deliberate, iterated change (stronger pull candidate)   |
| `commit_count == 1` matching initial deploy                 | Likely untouched since setup                            |
| Project `last_commit_date` > template `last_commit_date`    | Project evolved beyond template                         |
| Template `last_commit_date` > project deploy date           | Template updated, project is behind (likely `outdated`) |
| Commit message contains `fix:`, `improve:`, `feat:`, `add:` | Intentional improvement                                 |
| Commit message contains `wip`, `temp`, `hack`, `quick`      | Weak candidate, possibly accidental                     |

**Combined assessment approach:**

1. Read the diff between expected and actual
2. Check git history signals (commit count, dates, messages)
3. Weight both signals:
   - High commit count + improvement diff → strong `improvement`
   - Single commit + project-specific values → `project-specific`
   - Removed functionality + no replacement → `regression`
   - Template newer + project unchanged since deploy → `outdated` (reclassify from `modified`)

### Agent-Assisted Classification

After heuristic classification completes, dispatch agents for deeper analysis of ambiguous results.

**When to dispatch:**

- Any `modified` item with `confidence: medium` or `confidence: low`
- Any `custom` item (to assess generalizability)
- Skip when all modified items have `confidence: high` and no custom items exist

**Dispatch pattern:** Use `agent:parallel` when >3 items need analysis, otherwise `agent:dispatch` for each.

1. **MUST** dispatch `code-explorer` agent via `agent:dispatch` (or `agent:parallel`). Do NOT skip agent analysis when qualifying items exist:
   - **Prompt:** "Analyze the following infrastructure file modification. Compare the project version against the canonical template. Classify as improvement (benefits all projects), project-specific (tailored to this project), or regression (removes functionality). Assess whether the change is generalizable enough to be a pull candidate for the global catalog."
   - **Context per item:**
     - File path and category
     - Diff content (expected vs actual)
     - Git history summary (commit count, dates, messages)
     - Relevant project-constants.md values
   - **Expected output per item:**
     - Validated sub-type: `improvement` / `project-specific` / `regression`
     - Adjusted confidence: `high` / `medium` / `low`
     - Pull candidacy: `true` / `false` with rationale
     - Brief analysis summary (1-2 sentences)

2. Merge agent findings with heuristic results:
   - Agent assessment overrides heuristic classification when agent confidence is higher
   - If heuristic says `improvement (medium)` and agent says `project-specific (high)`, use agent result
   - If agent is unavailable or fails, fall back to heuristic-only classification
   - Log: `"Agent-assisted analysis: {available/unavailable}, {N} items analyzed"`

**Graceful fallback:** If agent dispatch fails or times out, continue with heuristic-only results. Log a warning but do not STOP the audit. This matches the pattern in `validate-code` where reviewer dispatch failure is logged but doesn't block.

### Pull Candidacy Assessment

For `custom` and `modified (improvement)` items:

| Field            | Value                                                                         |
| ---------------- | ----------------------------------------------------------------------------- |
| `pull_candidate` | `true` if generalizable AND `commit_count > 1` or commit message shows intent |
| `pull_notes`     | Brief description of what would need to be templatized                        |
| `protected`      | `true` if the item should never be overwritten by push                        |
| `confidence`     | `high` / `medium` / `low` based on git signal strength                        |

**Confidence rules:**

- `high` — multiple deliberate commits, clear improvement diff, no project-specific values
- `medium` — single intentional commit, improvement diff, minor project-specific values
- `low` — unclear commit history, mixed diff, needs manual review

### Outputs

- Per-file classification: synced / modified / outdated / missing / custom
- Pull candidacy assessments for custom and improvement items

### Exit Criteria

- All canonical catalog items classified; agent-assisted analysis merged (if applicable)

---

## Stage 4: Hook Wiring Analysis

### Inputs

- `<TARGET_PATH>/.claude/settings.json`
- Hook files in `<TARGET_PATH>/.claude/hooks/`
- Expected wiring from `settings.json.template`

### Activities

Analyze `<TARGET_PATH>/.claude/settings.json` for hook configuration health.

### Check For:

1. **Orphaned hooks** — Hook files exist in `.claude/hooks/` but are not wired in `settings.json`
2. **Unwired references** — `settings.json` references hook scripts that don't exist on disk
3. **Missing event bindings** — Standard hook-to-event mappings that are absent

### Standard Hook-Event Mappings

Compare against expected wiring from `settings.json.template`:

- `PreToolUse` events → safety hooks (protect-files, detect-secrets, hitl-approval, planning-guard)
- `PostToolUse` events → observability hooks (audit-log, checkpoint-save, error-detect, mcp-error-detect)
- `PreCompact` events → session hooks (pre-compact)
- `PostCompact` events → session hooks (context-recovery)
- Other events → remaining hooks per template configuration

### Outputs

- List of orphaned hooks, unwired references, and missing event bindings

### Exit Criteria

- Hook wiring analysis complete

---

## Stage 5: Standards Freshness Check

### Inputs

- `.claude/project-catalog.yaml` (for `standards.source_version`)
- `~/.claude/evolv-coder-standards/manifest.yaml` (latest domain versions)

### Activities

Check if the project's compiled standards are up to date with the standards repository.

### Check Standards Versions

1. Read the project's `project-catalog.yaml` for `standards.source_version` and per-domain versions
2. Update the standards cache:
   ```bash
   cd ~/.claude/evolv-coder-standards && git pull --ff-only
   ```
   If the cache does not exist and `gh` CLI is available:
   ```bash
   gh repo clone evolvconsulting/evolv-coder-standards ~/.claude/evolv-coder-standards
   ```
3. Read `~/.claude/evolv-coder-standards/manifest.yaml` for latest domain versions
4. Compare per-domain: flag stale domains

### Standards Freshness Report

```
| Domain | Local Version | Latest Version | Status |
|--------|--------------|----------------|--------|
| core-standards | {local} | {latest} | {OK/STALE/MISSING} |
| frontend-standards | {local} | {latest} | {OK/STALE/MISSING} |
| backend-standards | {local} | {latest} | {OK/STALE/MISSING} |
| database-standards | {local} | {latest} | {OK/STALE/MISSING} |
| devops-standards | {local} | {latest} | {OK/STALE/MISSING} |
| documentation-standards | {local} | {latest} | {OK/STALE/MISSING} |
```

### Factor into Health Score

- Each stale domain reduces health score by 2%
- Each missing domain reduces health score by 3%
- Standards freshness is weighted as 10% of total health score

**If cache missing and clone fails:** Skip standards freshness check:

```bash
printf '%b\n' "${YELLOW}[>]${RESET} Standards freshness check skipped"
printf '%b\n' "    ${DIM}Cache not found and repo unreachable.${RESET}"
printf '%b\n' "    ${DIM}Run: npx @evolvconsulting/evolv-coder-kit --global${RESET}"
```

### Outputs

- Per-domain freshness status (OK / STALE / MISSING)
- Health score adjustment for stale/missing standards

### Exit Criteria

- Standards freshness checked (or skipped with notice if cache unavailable)

---

## Stage 6: Reconciliation Report

### Inputs

- Classification results from Stage 3
- Hook wiring issues from Stage 4
- Standards freshness results from Stage 5

### Activities

Generate a comprehensive report.

### Report Format

Display the report header as a summary box, then show each section with status symbols.

**Report header:**

```bash
echo ""
printf '%b\n' "${ORANGE}${BOLD}Infrastructure Audit Report${RESET}"
echo ""
printf '%b\n' "Project: {PROJECT_NAME}"
printf '%b\n' "Path: {TARGET_PATH}"
printf '%b\n' "Audit Date: {DATE}"
printf '%b\n' "Catalog: v{catalog_version}"
printf '%b\n' "Deployed: {version or None}"
printf '%b\n' "Git History: {Yes/No}"
echo ""
```

**Health score banner:**

```bash
echo ""
printf '%b\n' "${ORANGE}${BOLD}Health Score: {percentage}% Synced${RESET}"
echo ""
```

**Summary table:** Display the category breakdown as a markdown table in the persisted report. For terminal display, show per-category status:

```bash
printf '%b\n' "${GREEN}[x]${RESET} Root files     {synced}/{total} synced"
printf '%b\n' "${YELLOW}[>]${RESET} Config         {synced}/{total} synced, {modified} modified"
printf '%b\n' "${GREEN}[x]${RESET} Agents         {synced}/{total} synced"
printf '%b\n' "${CYAN}[*]${RESET} Skills         {outdated} outdated"
printf '%b\n' "${RED}[!]${RESET} Hooks          {missing} missing"
printf '%b\n' "${GREEN}[x]${RESET} Primitives     {synced}/{total} synced"
printf '%b\n' "${DIM}[-]${RESET} Context        {custom} custom"
```

Use the appropriate status symbol per category:

- `[x]` green — all synced
- `[>]` yellow — has modified items
- `[*]` cyan — has outdated items
- `[!]` red — has missing items
- `[-]` dim — only custom items (no canonical counterpart)

**Modified items section:**

```bash
echo ""
printf '%b\n' "${ORANGE}${BOLD}Modified Items${RESET}"
echo ""
printf '%b\n' "${YELLOW}[>]${RESET} {file} — {sub-type}, {confidence} confidence"
printf '%b\n' "    ${DIM}{commits} commits, last changed {date}${RESET}"
printf '%b\n' "    ${DIM}Pull candidate: {Yes/No} — {summary}${RESET}"
```

**Outdated items section:**

```bash
echo ""
printf '%b\n' "${ORANGE}${BOLD}Outdated Items${RESET}"
echo ""
printf '%b\n' "${CYAN}[*]${RESET} {file} — template {gap} days newer"
printf '%b\n' "    ${DIM}Template: {template_date}  Project: {project_date}${RESET}"
```

**Missing items section:**

```bash
echo ""
printf '%b\n' "${ORANGE}${BOLD}Missing Items${RESET}"
echo ""
printf '%b\n' "${RED}[!]${RESET} {file} — {category}, required: {Yes/No}"
printf '%b\n' "    ${DIM}Impact: {what's affected}${RESET}"
```

**Custom items section:**

```bash
echo ""
printf '%b\n' "${ORANGE}${BOLD}Custom Items${RESET}"
echo ""
printf '%b\n' "${DIM}[-]${RESET} {file} — {commits} commits, {confidence} confidence"
printf '%b\n' "    ${DIM}Pull candidate: {Yes/No} — {notes}${RESET}"
```

**Standards freshness section:**

```bash
echo ""
printf '%b\n' "${ORANGE}${BOLD}Standards Freshness${RESET}"
echo ""
printf '%b\n' "${GREEN}[x]${RESET} core-standards       v{local} = v{latest}"
printf '%b\n' "${YELLOW}[>]${RESET} frontend-standards   v{local} < v{latest} (STALE)"
printf '%b\n' "${RED}[!]${RESET} backend-standards    MISSING"
```

Use `[x]` green for OK, `[>]` yellow for STALE, `[!]` red for MISSING.

**Hook wiring issues:**

```bash
echo ""
printf '%b\n' "${ORANGE}${BOLD}Hook Wiring Issues${RESET}"
echo ""
printf '%b\n' "${RED}[!]${RESET} Orphaned: {hook}"
printf '%b\n' "    ${DIM}Wire in settings.json or remove file${RESET}"
printf '%b\n' "${RED}[!]${RESET} Unwired: {event}"
printf '%b\n' "    ${DIM}Add hook file or remove reference${RESET}"
```

**Recommendations:**

```bash
echo ""
printf '%b\n' "${ORANGE}${BOLD}Recommendations${RESET}"
echo ""
printf '%b\n' "${CYAN}[*]${RESET} 1. {Prioritized recommendation}"
printf '%b\n' "${CYAN}[*]${RESET} 2. {Next recommendation}"
```

**What to do next — summary box:**

```bash
echo ""
printf '%b\n' "${ORANGE}${BOLD}What To Do Next${RESET}"
echo ""
printf '%b\n' "${RED}[!]${RESET} Missing: /eck:pull-from-global-catalog"
printf '%b\n' "${CYAN}[*]${RESET} Outdated: /eck:pull-from-global-catalog"
printf '%b\n' "${YELLOW}[>]${RESET} Improvements: /eck:push-to-user-catalog"
printf '%b\n' "${YELLOW}[>]${RESET} Stale stds: /eck:pull-from-standards"
printf '%b\n' "${DIM}[-]${RESET} No catalog: --write-catalog flag"
echo ""
```

Only display rows relevant to the audit findings. Omit rows where no items match that finding.

**All-clear fallback:** If no issues were found (100% synced, no modified/outdated/missing items, no hook wiring issues, no stale standards), display:

```bash
echo ""
printf '%b\n' "${GREEN}[x]${RESET} All clear — infrastructure is fully synced."
printf '%b\n' "    ${DIM}No action needed. Run /eck:audit-current-project for future checks.${RESET}"
echo ""
```

### Persisted Report

The full report saved to `$ECK_HOME/audits/` retains the detailed markdown table format for machine readability:

| Category   | Canonical | Found   | Synced  | Modified | Outdated | Missing | Custom  |
| ---------- | --------- | ------- | ------- | -------- | -------- | ------- | ------- |
| Root files | {N}       | {N}     | {N}     | {N}      | {N}      | {N}     | {N}     |
| Config     | {N}       | {N}     | {N}     | {N}      | {N}      | {N}     | {N}     |
| Agents     | {N}       | {N}     | {N}     | {N}      | {N}      | {N}     | {N}     |
| Skills     | {N}       | {N}     | {N}     | {N}      | {N}      | {N}     | {N}     |
| Hooks      | {N}       | {N}     | {N}     | {N}      | {N}      | {N}     | {N}     |
| Primitives | {N}       | {N}     | {N}     | {N}      | {N}      | {N}     | {N}     |
| Context    | {N}       | {N}     | {N}     | {N}      | {N}      | {N}     | {N}     |
| **Total**  | **{N}**   | **{N}** | **{N}** | **{N}**  | **{N}**  | **{N}** | **{N}** |

### Outputs

- Comprehensive reconciliation report displayed in terminal
- Full markdown report ready for persisting in Stage 7

### Exit Criteria

- Report generated with all sections populated

---

## Stage 7: Persist Audit Report

### Inputs

- Full reconciliation report from Stage 6

### Activities

**Always execute.** Save the audit report to `$ECK_HOME/audits/` for project tracking.

### Report Location

```
$ECK_HOME/audits/{project-name}-{YYYY-MM-DD}.md
```

Where `{project-name}` is derived from `<PROJECT_KEY>` lowercased or the project directory name.

**Examples:**

- `$ECK_HOME/audits/evolv-coder-2026-02-25.md`
- `$ECK_HOME/audits/my-saas-app-2026-02-25.md`

### Write Rules

1. If a report already exists for this project + date, overwrite it (re-audit replaces stale report)
2. The report content is the full reconciliation report from Stage 6
3. Create the `$ECK_HOME/audits/` directory if it doesn't exist

```bash
mkdir -p $ECK_HOME/audits/
```

### Outputs

- Audit report written to `$ECK_HOME/audits/{project-name}-<DATE>.md`

### Exit Criteria

- Report file exists on disk

---

## Stage 8: Update Registry

### Inputs

- Audit results from Stages 3-6
- `$ECK_HOME/registry.yaml` (if exists)

### Activities

**Always execute after Stage 7.** Update the project registry with audit results.

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

Read `$ECK_HOME/registry.yaml`. If it does not exist, log a warning and skip registry update (the installer creates the registry during `--global` install).

### Update Project Entry

Read `$ECK_HOME/registry.yaml` and update the audited project's entry:

1. **Update `last_audit` section:**

   ```yaml
   last_audit:
     date: "{DATE}"
     report_path: "audits/{project-name}-{DATE}.md"
     health_score: { computed_health_score }
     health_grade: "{GRADE}"
     synced: { N }
     modified: { N }
     outdated: { N }
     missing: { N }
     custom: { N }
   ```

2. **Set `audit_status`** based on health_score:
   - `>=75` → `audit_status: "passing"`
   - `<75` → `audit_status: "failing"`

3. **Update `pull_candidates` array:**
   - Merge `pull_candidates` per the `ops:registry-update` primitive Step 4.5 (merge by file path, preserve reviewed items).
   - Include file path, type (custom/improvement), confidence, and description

4. **Update `deployment.has_deployed_catalog`:**
   - Set to `true` if `--write-catalog` was used or catalog already exists
   - Set to `false` otherwise

5. **Set `last_modified_at`** to current ISO-8601 date.

6. **Append to `sync_history`:**
   ```yaml
   - date: "{DATE}"
     action: "audit"
     performed_by: "/eck:audit-unmanaged-project"
     summary: "Infrastructure audit: health {GRADE} ({SCORE}%), {N} synced, {N} modified, {N} outdated"
   ```

### New Project Handling

If the audited project is NOT in the registry:

1. Check for KEY_CONFLICT and PATH_CONFLICT per `ops:registry-update` primitive Step 1.5.
2. Create a new entry with all fields populated from audit data
3. Set `project_name` from project-constants.md or directory basename
4. Set `project_path` to absolute path of audited project
5. Set `state: "discovered"`
6. Set `audit_status` based on health_score (`>=75` → `"passing"`, `<75` → `"failing"`)
7. Infer `tracker_type` and `doc_platform` from project-constants.md
8. Set `divergence_policy: standard` (default)
9. Set `dev_rigor: null`, `learning_autonomy: null`
10. Set `pull_candidates: []` and `sync_history: []`
11. Set `deployment.initial_deploy_date` from earliest git commit on `.claude/` files
12. Inform user: `"New project '{project_name}' added to $ECK_HOME/registry.yaml"`

### Recompute Project Summary

After updating the project entry, recompute the `project_summary` section per the `ops:registry-update` primitive:

- Recalculate `total_projects`, `active_projects`
- Recalculate `by_tracker`, `by_platform`, `by_template_version` counts
- Recalculate `health_distribution` buckets
- Recalculate `health_stats` (average, median, highest, lowest)
- Recalculate `totals` (sum of synced/modified/outdated/missing/custom across all projects)
- Update `pull_candidates_total` count
- Update `pull_candidates_pending` count (count of pull_candidates entries where status == "pending")
- Update `projects_with_deployed_catalog` count
- Update `last_project_audit` date

### Write

Atomic write: write to `registry.yaml.tmp`, then rename to `registry.yaml`.

### Outputs

- `registry.yaml` updated with audit results, pull candidates, and sync history entry
- New project entry created if not previously registered

### Exit Criteria

- Registry updated (or warning logged if registry absent)

---

## Stage 9: Catalog Write (Opt-In)

### Inputs

- Classification results from Stage 3
- `--write-catalog` flag (must be present)

### Activities

**Only execute if `--write-catalog` flag was specified or user explicitly requests it.**

### Generate Deployed Catalog

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

```yaml
# Catalog - Deployed Instance
# Generated by /eck:audit-unmanaged-project
# Source: evolv-coder-kit templates v{template_version}

catalog_version: "2.0.0"
claude_code_standards_version: "{claude_code_standards_version}"
template_version: "{template_version}"
project_name: "{PROJECT_NAME}"
project_key: "{PROJECT_KEY}"

deployed_at: "{DATE}"
deployed_by: "/eck:audit-unmanaged-project"
last_audit: "{DATE}"

# Component statuses from audit
components:
  {category}:
    - name: "{name}"
      file: "{relative_path}"
      version: "{version}"
      checksum: "{actual_checksum}"
      canonical_checksum: "{canonical_checksum}"
      status: "{synced|modified|outdated|missing|custom}"
      # Git metadata
      last_commit_hash: "{hash}"
      last_commit_date: "{date}"
      last_commit_message: "{message}"
      commit_count: {N}
      # For modified items:
      modification_type: "{improvement|project-specific|regression}"
      pull_candidate: {true|false}
      pull_confidence: "{high|medium|low}"
      pull_notes: "{notes}"
      protected: {true|false}
      # For custom items:
      custom: true
      pull_candidate: {true|false}
      pull_confidence: "{high|medium|low}"
      pull_notes: "{notes}"
      protected: {true|false}

# Sync history log
sync_history:
  - date: "{DATE}"
    action: "audit"
    performed_by: "/eck:audit-unmanaged-project"
    claude_code_standards_version: "{claude_code_standards_version}"
    report_path: "$ECK_HOME/audits/{project-name}-{DATE}.md"
    summary: "Audit: {N} synced, {N} modified, {N} outdated, {N} missing, {N} custom"
```

### Validation

After writing:

```bash
# Verify YAML is valid
python3 -c "import yaml; yaml.safe_load(open('{TARGET_PATH}/.claude/project-catalog.yaml'))"
```

### Outputs

- `<TARGET_PATH>/.claude/project-catalog.yaml` written with full component inventory

### Exit Criteria

- Catalog YAML written and validated; skipped if `--write-catalog` not specified

---

## Conditional Deployment Awareness

When classifying items, respect deployment conditions from the canonical catalog:

| Condition                        | Skip If                              |
| -------------------------------- | ------------------------------------ |
| `TRACKER_TYPE == JIRA`           | Project uses GitHub Issues or Linear |
| `TRACKER_TYPE == GitHub Issues`  | Project uses JIRA or Linear          |
| `DOC_PLATFORM == Confluence`     | Project uses Local markdown          |
| `DOC_PLATFORM == Local markdown` | Project uses Confluence              |

Items that are conditionally excluded based on the project's configuration should NOT be reported as "missing". Instead, they are simply not applicable.

**Detection:** Read `project-constants.md` for `<TRACKER_TYPE>` and `<DOC_PLATFORM>` values. If these cannot be determined, report conditional items separately with a note.

---

## Error Handling

### Canonical Catalog Not Found

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

### Target Not a Claude Code Project

```bash
printf '%b\n' "${RED}[!]${RESET} No .claude/ directory found at {TARGET_PATH}"
printf '%b\n' "    ${DIM}This project has no Claude Code infrastructure.${RESET}"
printf '%b\n' "    ${DIM}Consider running /eck:new-project to bootstrap it.${RESET}"
```

### Project Constants Unreadable

```bash
printf '%b\n' "${YELLOW}[>]${RESET} Cannot read {TARGET_PATH}/.claude/project-constants.md"
printf '%b\n' "    ${DIM}Placeholder-aware diffing disabled.${RESET}"
printf '%b\n' "    ${DIM}Template-sourced files may show as modified.${RESET}"
```

### Git Not Available in Target

```bash
printf '%b\n' "${YELLOW}[>]${RESET} Git history not available for {TARGET_PATH}"
printf '%b\n' "    ${DIM}Using checksum + diff analysis only.${RESET}"
printf '%b\n' "    ${DIM}Pull candidate confidence will default to low.${RESET}"
```

---

## Related Documents

- [Global Catalog]($ECK_HOME/global-catalog.yaml) - Canonical source of truth
- [/eck:pull-from-global-catalog skill](../pull-from-global-catalog/SKILL.md) - Pull catalog updates into projects
- [/eck:push-to-user-catalog skill](../push-to-user-catalog/SKILL.md) - Push improvements back to catalog
- [/eck:migrate-project skill](../migrate-project/SKILL.md) - Onboard unmanaged projects
- [/eck:new-project skill](../new-project/SKILL.md) - Bootstrap new projects
