# Anysite Crm Audit

> Read-only data quality audit of the connected CRM - field completeness per mapped property, duplicate candidates, stale records, enrichability estimate. Produces a report and a concrete fix plan, never writes anything - run it first when you don't yet know what's broken; the actual fixing happens in anysite-crm-enrich. Use when the user asks "what's the state of my CRM", wants a data quality report, duplicate check, or a safe first run after connecting a CRM. Requires an active CRM connection.

- Skill: `anysiteio/anysite-crm-audit` (Agent Skill)
- Install (CLI): `npx skillmds@latest add anysiteio/anysite-crm-audit`
- Raw SKILL.md: https://api.skillmd.com/api/skills/anysiteio/anysite-crm-audit/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: anysiteio (https://skillmd.com/u/anysiteio)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/anysiteio/anysite-crm-audit

---


# CRM Audit

The safe first date with a user's CRM: read everything, write nothing, show what's broken
and what enrichment would fix. Also the natural funnel into `anysite-crm-enrich`.

## Prerequisites

Active CRM connection. No profile needed (works better with one — gap analysis follows the
mapped fields).

## Flow

### 1. Inventory

```
crm_get_schema(object_type="contacts") / (object_type="companies")
```
Use `properties` filtering when you only need specific fields — the full schema is large.
Then page through records:
```
crm_query_records(object_type=..., properties=[key fields], after=<cursor>)
```
Audit scope: whole portal if small; else the working list + a stated sample. Say which.

### 2. Analyze (all local — no further API calls)

- **Completeness:** % filled per mapped/target field (email, title, company, domain,
  industry, size, linkedin_url). Rank by gap size.
- **Match-key coverage:** how many contacts have email / linkedin_url / neither (the
  "neither" group is unenrichable and un-dedupable — flag it).
- **Duplicate candidates:** same normalized email; same domain with several company records;
  same person name + company. Candidates only — never auto-merge.
- **Email ↔ employer mismatch:** contact's email domain vs their linked company's domain.
  A mismatch has THREE causes needing different handling (all seen live): the person changed
  jobs; the COMPANY rebranded/changed domain (old domain usually still receives mail — the
  contact is fine); or the email is genuinely stale. Free discriminator already in the data:
  if crunchbase under the domain-derived alias returns a different company NAME than the
  LinkedIn page of that same domain — that's a rebrand, not a departure. FLAG ONLY, never
  auto-fix in either direction — in two causes out of three there is nothing to "fix", and
  "correcting" the company from the email domain overwrites good data with stale. Job-change
  suspects go to anysite-crm-champions.
- **Staleness:** if `anysite_last_enriched_at` (or similar) is mapped — age distribution;
  contacts with no activity fields; companies with dead domains (spot-check a few via
  `webparser/parse` only if the user asks).
- **Association health:** contacts without a company link (visible as missing company
  fields when queried).

### 3. Report

Lead with the 3 numbers that matter: enrichable-now count, duplicate-candidate count,
unenrichable count. Then per-field completeness table, then the fix plan:

- "N contacts have linkedin_url but no title → `anysite-crm-enrich` fills them (~cost)"
- "N companies missing industry/size → enrich via company lookup (~cost)"
- "N duplicate candidates → list for manual review (merging is a CRM-side operation)"

Cost estimates come from the anysite-mcp source map (credits per call × volume). Offer to
run the enrichment as the next step — do not run it from this skill.

## Hard rule

This skill performs zero writes: no upserts, no dry-runs, no "small fixes". Its value is
that it is provably safe to run on day one.

