contact-manager

Normalize, classify, and manage contact databases across 3 Gmail accounts. Clean CSV exports, deduplicate, tag categories, flag touchbase/unsubscribe candidates.

5 stars

Best use case

contact-manager is best used when you need a repeatable AI agent workflow instead of a one-off prompt.

Normalize, classify, and manage contact databases across 3 Gmail accounts. Clean CSV exports, deduplicate, tag categories, flag touchbase/unsubscribe candidates.

Teams using contact-manager should expect a more consistent output, faster repeated execution, less prompt rewriting.

When to use this skill

  • You want a reusable workflow that can be run more than once with consistent structure.

When not to use this skill

  • You only need a quick one-off answer and do not need a reusable workflow.
  • You cannot install or maintain the underlying files, dependencies, or repository context.

Installation

Claude Code / Cursor / Codex

$curl -o ~/.claude/skills/contact-manager/SKILL.md --create-dirs "https://raw.githubusercontent.com/vamseeachanta/workspace-hub/main/.agents/skills/email/contact-manager/SKILL.md"

Manual Installation

  1. Download SKILL.md from GitHub
  2. Place it in .claude/skills/contact-manager/SKILL.md inside your project
  3. Restart your AI agent — it will auto-discover the skill

How contact-manager Compares

Feature / Agentcontact-managerStandard Approach
Platform SupportNot specifiedLimited / Varies
Context Awareness High Baseline
Installation ComplexityUnknownN/A

Frequently Asked Questions

What does this skill do?

Normalize, classify, and manage contact databases across 3 Gmail accounts. Clean CSV exports, deduplicate, tag categories, flag touchbase/unsubscribe candidates.

Where can I find the source code?

You can find the source code on GitHub using the link provided at the top of the page.

SKILL.md Source

# Contact Manager

Normalize and classify contact databases for multi-account Gmail management.

## Contact Sources

| Account | Source Path | Format | Entries |
|---|---|---|---|
| ace | aceengineer-admin/admin/contacts/aceengineer_contacts.csv | Outlook CSV export | ~1,306 |
| personal | aceengineer-admin/admin/contacts/achantav_contacts.csv | Outlook CSV export | ~1,157 |
| skestates | sabithaandkrishnaestates/admin/contacts/ | Manual (from key_contacts.md) | ~20 |

## Normalization Steps

### Step 1: Parse and clean CSV

Known issues in the raw CSVs:
- Email addresses wrapped in angle brackets: `<email@domain.com>`
- Empty name fields with only email
- Duplicate entries (same person, multiple rows)
- Craigslist/spam entries mixed in
- Malformed CSV escaping (quotes inside fields)
- BOM encoding (use utf-8-sig)
- Outlook export has 64 columns with verbose names
- First Name field often contains the email in angle brackets

### Step 2: Create normalized schema

Output format (per account): `contacts_normalized.csv`

```csv
email,first_name,last_name,company,category,touchbase_cadence,notes
```

For SKEstates (expanded schema with department/phone):
```csv
email,first_name,last_name,title,company,department,category,touchbase_cadence,phone,notes
```

### Step 3: Category classification

Categories:
- `client` — current/past clients (EPCI operators, engineering firms)
- `colleague` — current/former colleagues, same-company contacts
- `vendor` — service providers, suppliers
- `recruiter` — staffing, job-related contacts
- `industry` — industry organizations, standards bodies
- `alumni` — university contacts (Rice, TAMU, UT McCombs)
- `personal` — friends, family (gmail/yahoo with known names)
- `financial` — banks, insurance, investment
- `government` — tax, legal, regulatory
- `newsletter` — subscriptions, marketing lists
- `spam` — junk, craigslist, unknown bulk
- `tenant` — tenant contacts (for real estate accounts)
- `vendor-functional` — shared functional inboxes (no touchbase)
- `tenant-functional` — shared tenant inboxes

#### Engineered domain mappings (from iteration on 2,400+ contacts)

**Ace client domains:**
```
ril.com, lng-agroup.com, mcdermott.com, shell.com, kbr.com,
technip.com, technipfmc.com, subsea7.com, nov.com, aker.com,
bp.com, awilcodrilling.com, eagle.org, vulcanoffshore.com,
boptechnologies.com, risersinc.com, sandsig.com,
engineeredcustomsolutions.com, mecorparada.com.ve
```

**Ace colleague domains:**
```
trendsetterengineering.com, spire-engineers.com,
2hoffshoreinc.com, 2hoffshore.com, prospricing.com
```

**Ace vendor domains:**
```
disys.com, winworldinfo.com, partneresi.com, ansys.com,
akselos.com, engys.com, dnvgl.com, tescocorp.com,
deccaconsulting.com, flooranddecor.com, pulse-monitoring.com,
quantumep.com, acematrix.com
```

**Ace recruiter domains:**
```
stepstoprogress.com, thejukesgroup.com, apexsystems.com,
indianeagle.com
```

**Ace industry domains:**
```
km.kongsberg.com, ceesol.com
```

**Personal alumni domains:**
```
rice.edu, mccombs.utexas.edu, neo.tamu.edu, tamu.edu, houstonisd.org
```

**Personal financial domains:**
```
aaa-texas.com, colehealth.com, harkandgroup.com, aol.com,
sbcglobal.net, constellation.com
```

**Spam domains (auto-remove):**
```
sale.craigslist.org, talkmatch.com
```

**Spam patterns (regex):**
```
unsubscribe, no.?reply, noreply, do.?not.?reply
mailer-daemon, postmaster@, bounce@
@unsubscribe2\., \.unsubscribe\., @sailthru\., @mcsv\., @rsys5\., @customer\.io
```

**Spam name fragments:**
```
craigslist, mailer-daemon, unsubscribe, academia.edu, 123greetings, machinemetrics
```

### Step 4: Intra-file deduplication

Rules:
- Same primary email → keep first occurrence
- Same name, different email → keep both, flag for review
- No name, only email → try to derive name from email prefix

### Step 5: Cross-file deduplication

132 overlaps found between ace and personal files. Decision rules (applied in order):

1. `aceengineer.com` → ace only (internal domain)
2. `achanta` in email prefix → personal only (family)
3. Company domain (not gmail/yahoo/hotmail) → ace only (professional)
4. Personal email with company tag in source → ace only
5. Personal email with company in ace record → ace only
6. Both unknown, personal email → personal only
7. Ace has real classification → ace wins

Result: 122 moved from personal to ace, 10 kept in personal.
Zero remaining overlaps.

Report template: `reports/email/contact-dedup-report.md`

## Scripts

### Contact normalizer (run with uv)
```bash
uv run scripts/email/contact-normalizer.py
```

Input: raw Outlook CSV exports from both accounts.
Output: `aceengineer_normalized.csv` (1,281 contacts) + `achantav_normalized.csv` (994 contacts).

### SKEstates contact builder
Built from two markdown files:
- `key_contacts.md` (3 PCA vendor contacts)
- `fd_corporate_contact_maintenance.md` (22 Family Dollar/Dollar Tree staff)

Output: `sabithaandkrishnaestates/admin/contacts/skestates_contacts.csv` (25 contacts).
# Count unknown domains to discover missing mappings
unknown_domains = Counter(r["email"].split("@")[-1] for r in contacts if r["category"] == "unknown")
for domain, count in unknown_domains.most_common(20):
    print(f"  {domain:40s} {count}")
```

Then expand the domain classification sets (ACE_CLIENT_DOMAINS, ACE_VENDOR_DOMAINS, etc.)
in the normalizer script and re-run. Second pass typically reaches 80%+ classification.

### Step 4: Cross-file deduplication

When contacts appear in multiple account files (email addresses imported into
multiple Outlook exports), resolve overlaps using these rules:

| Signal | Canonical Home | Rationale |
|---|---|---|
| aceengineer.com domain | ace | Internal domain |
| achantav* in email prefix | personal | Family email |
| Company domain (non-gmail/yahoo) | ace | Professional contact |
| Personal email with company in record | ace | Cross-referenced professional |
| Both unknown, personal email | personal | No business value |
| Ace has classification | ace | Already categorized |

After dedup: annotate the canonical file with cross-ref note, remove from duplicate file.

### Step 5: Write output files

## Scripts

### Contact normalizer (run with uv)
```bash
uv run scripts/email/contact-normalizer.py
```
The normalizer processes ALL accounts in one run. It reads both raw CSVs and outputs normalized files alongside them. No CLI args needed — paths are hardcoded for the workspace-hub convention.

### Re-running after adding domain mappings
Edit the domain sets in `scripts/email/contact-normalizer.py` (ACE_CLIENT_DOMAINS, ACE_VENDOR_DOMAINS, etc.) then re-run. The script is idempotent.

## File Locations (post-normalization)

| Account | Normalized CSV | Classified CSV |
|---|---|---|
| ace | aceengineer-admin/admin/contacts/aceengineer_normalized.csv | aceengineer-admin/admin/contacts/aceengineer_classified.csv |
| personal | aceengineer-admin/admin/contacts/achantav_normalized.csv | aceengineer-admin/admin/contacts/achantav_classified.csv |
| skestates | sabithaandkrishnaestates/admin/contacts/skestates_contacts.csv | (small enough to classify manually) |

## Pitfalls

1. Outlook CSV export has 64 columns with verbose names ("E-mail Address", "E-mail 2 Address", etc.)
2. Email addresses often wrapped in angle brackets: `<email@domain.com>`
3. Some entries have email stored in "First Name" field when name is unknown
4. Windows BOM (utf-8-sig) — always open with `encoding="utf-8-sig"`
5. Empty first/last name rows are common (~30-36% of contacts) — use email prefix for name inference
6. Cross-file email overlap is guaranteed (~132 of ~2,400) — always dedup after normalizing
7. External repos (aceengineer-admin, sabithaandkrishnaestates) must be committed from within their own git dirs
8. Legal scan: contact CSVs may contain client names — run `.legal-deny-list.yaml` scan before committing
9. Don't delete raw Outlook exports — keep originals, create `_normalized.csv` alongside
10. Domain inference from email prefix is heuristic-only — tag uncertain results for manual review
3. Don't delete raw CSVs — keep originals, create normalized copies alongside
4. Legal: contact data is PII — never commit to public repos, .gitignore if needed
5. The personal CSV has craigslist/talkmatch spam entries — auto-classify as spam
6. Company field often empty — try to infer from email domain
7. External repos (aceengineer-admin, sabithaandkrishnaestates) are separate git repos — `cd` into them to commit, don't use `git add` from workspace-hub root
8. First-pass domain classification yields ~20% — ALWAYS run the unknown-domain-frequency analysis and expand mappings before claiming done
9. The contact-normalizer.py script lives in workspace-hub root (`scripts/email/`) but reads/writes in repo subdirectories — it finds the root by walking up from its own path

Related Skills

background-service-manager

5
from vamseeachanta/workspace-hub

Create and manage long-running background processes with start/stop/status controls, logging, and monitoring. Use for batch processing jobs, data pipelines, continuous services, or any long-running tasks.

orcaflex-batch-manager

5
from vamseeachanta/workspace-hub

Manage large-scale OrcaFlex batch processing with parallel execution, adaptive worker scaling, memory optimization, and progress tracking for efficient simulation campaigns.

github-release-manager

5
from vamseeachanta/workspace-hub

Automated release coordination and deployment with swarm orchestration for seamless version management, testing, and deployment across multiple packages. Use for release pipelines, version coordination, deployment orchestration, and release documentation.

github-pr-manager

5
from vamseeachanta/workspace-hub

Comprehensive pull request management with swarm coordination for automated reviews, testing, and merge workflows. Use for PR lifecycle management, multi-reviewer coordination, conflict resolution, and intelligent branch management.

state-directory-manager-5-cache-management

5
from vamseeachanta/workspace-hub

Sub-skill of state-directory-manager: 5. Cache Management (+1).

state-directory-manager-4-state-file-operations

5
from vamseeachanta/workspace-hub

Sub-skill of state-directory-manager: 4. State File Operations.

state-directory-manager-1-xdg-base-directory-standard

5
from vamseeachanta/workspace-hub

XDG Base Directory compliant state management. Use when setting up config, data, state, or cache directories per the XDG specification.

git-sync-manager-5-safe-branch-operations

5
from vamseeachanta/workspace-hub

Sub-skill of git-sync-manager: 5. Safe Branch Operations.

git-sync-manager-3-repository-status-check

5
from vamseeachanta/workspace-hub

Sub-skill of git-sync-manager: 3. Repository Status Check (+1).

git-sync-manager-2-multi-phase-sync-pattern

5
from vamseeachanta/workspace-hub

Sub-skill of git-sync-manager: 2. Multi-Phase Sync Pattern.

git-sync-manager-1-repository-discovery-from-gitignore

5
from vamseeachanta/workspace-hub

Sub-skill of git-sync-manager: 1. Repository Discovery from .gitignore.

git-sync-manager-1-always-check-before-operating

5
from vamseeachanta/workspace-hub

Sub-skill of git-sync-manager: 1. Always Check Before Operating (+4).