# Contacts And Crm

> Resolve a name or partial address to a real email and enrich a thread with CRM/contact context (HubSpot, Apollo) before drafting or triaging. Use when the user names a person instead of an email, or asks "who is this" / "what deals/tickets does this contact have".

- Skill: `builderio/contacts-and-crm` (Agent Skill)
- Install (CLI): `npx skillmds@latest add builderio/contacts-and-crm`
- Raw SKILL.md: https://api.skillmd.com/api/skills/builderio/contacts-and-crm/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- Author: Builder.io (https://skillmd.com/u/builderio)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/builderio/contacts-and-crm

---


# Contacts and CRM

## Resolving a recipient

Use `find-contact` before asking the user for someone's email address, and
before guessing a pattern like `firstinitiallastname@company.com`.

`find-contact` is backed by `loadContactsForEmail`, which merges Google People
API "connections" (boosted `count += 5`) and "other contacts" with real
send/receive history. Because it sees actual interaction history, it is strictly
better than guessing an address pattern.

- `find-contact --query="<name or partial email>" --limit=5` matches
  case-insensitively against name and email, splitting the query into
  whitespace-separated terms that must ALL match (`"jacqueline lamb"` requires
  both terms present).
- Results are sorted by `count`, an interaction-frequency score. Google People
  API "connections" (explicitly saved contacts) start at `count: 5`; "other
  contacts" (people the user has emailed but not saved) start lower. Sending
  or receiving mail increments a real `sendCount`/`receiveCount` in the
  `contact_frequency` SQL table, so the top match is usually the person the
  user actually means.
- If `find-contact` returns zero matches, tell the user — do not invent an
  email address. A wrong guess either bounces or, worse, silently reaches the
  wrong inbox.
- Results are cached per-owner for a few minutes (`contactCache` in
  `server/handlers/emails.ts`). A contact added in Google Contacts moments ago
  may not appear immediately; that's expected, not a bug to route around.

## CRM enrichment

- `get-hubspot-contact --email=<address>` is the only first-class CRM action.
  It returns contact fields (name, phone, company, title, lifecycle stage,
  lead status) plus up to 5 associated deals and up to 5 associated tickets,
  reading the user's own HubSpot API key configured in Settings. If no key is
  configured it returns `{ error: "HubSpot API key not configured" }` —
  surface that plainly rather than treating it as "no CRM data exists."
- **Gong, Pylon, and Apollo are UI-only in Mail.** They have server route
  handlers (`server/handlers/gong.ts`, `pylon.ts`, `apollo.ts`) that power the
  CRM sidebar panel in the email view, each reading its own per-session API
  key from `appStateGet`. None of the three is registered in Mail's
  `MAIL_PROVIDER_API_IDS` (see `listProviderApiIdsForTemplateUse("mail")` in
  `server/lib/provider-api.ts`, which currently resolves to `gmail`,
  `google_calendar`, and `hubspot` only). This means:
  - There is no agent action for Gong calls, Pylon tickets, or Apollo person
    lookups in Mail.
  - `provider-api-request` will refuse `provider: "gong"`, `"pylon"`, or
    `"apollo"` in this app even though those provider ids exist in the shared
    catalog — they're enabled for other templates (e.g. Analytics), not Mail.
  - If the user asks the agent to pull a Gong call or Pylon ticket from Mail,
    say plainly that integration is visible in the UI sidebar only today; do
    not fabricate a result or imply `provider-api-request` can reach it.
- **Provider API-key connections are Settings-UI only.** Gong, Pylon, Apollo,
  and HubSpot keys are saved through raw `/api/*` routes from the Settings UI —
  there are no `save-*-key` actions. The agent can read HubSpot data via
  `get-hubspot-contact` but cannot configure any of these connections on the
  user's behalf; ask the user to add the key in Settings.
- For HubSpot data outside contact lookup (deals search, ticket creation,
  property metadata), use `provider-api-catalog` / `provider-api-docs` with
  `provider: "hubspot"`, then `provider-api-request` — `get-hubspot-contact`
  only covers the single "lookup by email" shape.

## Related Skills

- `email-drafts` — use resolved contacts and CRM context when composing.
- `draft-queue` — resolving the right `ownerEmail` teammate uses
  `list-org-members`, a separate lookup from `find-contact`.
- `actions` — the shared provider API pattern for `provider-api-request`.

