---
name: moltsets-find-person
description: Use this skill whenever the user wants to find or look up a person by name and company - but does NOT already have a LinkedIn URL for them.
---

# Find Person

Resolve a person from a name + company. Prefer `MoltSets:search_linkedin_profile` (name + company in one call). Fall back to `MoltSets:search_people` to pull contacts at the company and match the target person by name.

## Triggers

Triggers include phrases like "find me [Name]", "look up [Name] at [Company]", "can you find [Name]", "search for someone named [Name]", or any request to locate a specific person without a LinkedIn URL already provided. Do NOT use this skill if the user already has a LinkedIn URL - use the enrich-contact skill instead.

## What the tools accept

**Preferred - `search_linkedin_profile`** (name + company → LinkedIn profile in one call):
- `name` OR (`first_name` + `last_name`) - the person you're looking for.
- `company` (name) OR `company_domain` (exact domain, e.g. `acme.com`).
- `count_only` (bool, free) - check whether a match exists without spending a credit.

**Fallback - `search_people`** (search by name and/or filter by company attributes). It DOES accept people-level filters now. Params:

- `query` - free-text across full name, company, and title. Put the person's NAME or role keywords here to search by name directly.
- `company` - company name. `company_domain` - exact company domain (e.g. `acme.com`), no protocol. (Note: the param is `company_domain`, not `domain`.)
- `seniority`, `industry`, `department`, `functional_area`, `country` - optional people filters (map the user's words to the exact enum values; use either `department` or `functional_area`, not both).
- `limit` - default 10, max 25 per page. `offset` - pagination; increase to page deeper.

Each `search_people` record includes `full_name`, `first_name`, `last_name`, `title`, `seniority`, `country`, `headline`, `linkedin_url`, `business_email`, company data, and `_score`. You can search by name via `query`; if several people share the name, confirm the right one against `title`/`company` in the records.

## Set Expectations

Before firing any calls, give the user a brief, dry heads-up on what's about to happen. Deadpan over enthusiastic - no filler, no corporate speak.

Facts to convey:
- A name + company lookup (or a company search with a name match on fallback)
- A few seconds total
- If the preferred lookup misses, you'll fall back to `search_people`, page deeper, or retry by company name before giving up

## Risk scores - confirm before enriching

Every email MoltSets returns carries a deliverability risk score - a grade from A to F. Ask which grades to keep before running anything:

> "MoltSets grades email deliverability risk from A (best) to F (no data). Which grades should I keep? I'd recommend **A, B, C and F** - and dropping **D**, since D is a confirmed bounce, complaint or spam trap."

| Grade | Meaning | Best practice |
| --- | --- | --- |
| A | Strongest engagement signal available | Safe to send immediately |
| B | Solid | Fine in regular sends; on a new or warming domain, send a smaller batch before scaling |
| C | Deliverability can't be confirmed | Segment separately from A/B, warm at low volume, watch engagement, suppress non-responders after 1-2 attempts |
| D | Confirmed bounce, complaint or spam trap | Never send - fastest way to trip spam traps and damage sender reputation for the whole list |
| F | No data - unknown risk, not "safe" | Re-verify before sending, or treat like C |

Use whatever set the user confirms. Treat the grade as a filter, not a guarantee - it lowers risk, it doesn't remove it. Pair it with the user's own sending domain reputation and list hygiene.

## `search_people` filters and best practice

Full request parameter set:

| Purpose | Param | Notes |
|---|---|---|
| Free text | `query` | Searches `full_name`, `first_name`, `last_name`, company name, `title` (~85% filled), `headline` (~65% filled). Names and role keywords only |
| Company name | `company` | Analysed match - every word you pass must appear in the stored name |
| Company domain | `company_domain` | Exact; full URLs are normalised automatically |
| Country | `country` | ~99% filled - the most reliable filter available |
| State / region | `state` | The person's location. Full names - "Texas", not "TX" |
| City | `city` | The exact stored city, **not** its suburbs. Pair with `state`/`country` to disambiguate repeated names |
| Seniority | `seniority` | ~60% filled. Intern, Entry, Senior, Manager, Director, VP, Head, C Suite, Owner, Partner |
| Department | `department` | ~60% filled. Shares its data with `functional_area` - use one |
| Functional area | `functional_area` | Same underlying data as `department` - never send both |
| Industry (broad) | `industry` | ~60% filled. 21 broad buckets |
| Industry (niche) | `linkedin_industry` | ~50% filled. LinkedIn's own ~150 labels - "Staffing and Recruiting", "Wellness and Fitness Services" |
| Industry (code) | `naics_code` | ~50% filled. Any hierarchy level - "54" is broad, "541120" is surgical |
| Employer size | `employee_range` | Filters the person's **current employer** - no company lookup needed first |
| Employer revenue | `revenue_range` | Same - applied to the person's current employer |
| Paging | `limit` / `offset` | 10 default, 25 max (5 on the Free plan) |

**Filters are free precision.** Execution cost is driven by the free-text `query`, not by the filters attached to it.

| Query shape | Relative cost to execute |
|---|---|
| `query` alone | baseline |
| `query` + any number of filters | the same - filters add nothing |
| filters only, no `query` | **~40x cheaper** |

- **Never send a bare `query`.** Attaching `country` costs nothing and removes every other market. A query-only call is the least precise shape available and no cheaper than a filtered one.
- **Drop `query` entirely when filters carry the whole intent.** "VPs of sales at US software companies" is fully expressible as `seniority` + `department` + `industry` + `country`, and runs ~40x cheaper as a pure filter search.
- Billing doesn't change either way - tokens are charged per record returned. This is about speed and search load.
- If all you have is free text, add `country`: highest fill rate of any filter, so it discards almost no legitimate match.

**Don't over-stack sparse filters.** Every non-`query` filter is an exact match and silently discards records where that field is empty. Three ~60%-filled filters can cut a viable audience to nothing. When a search comes back thin, drop the sparsest filter first (`naics_code`, `linkedin_industry`) or shorten the NAICS code - not `country`.

**Exact strings matter.** `"C Suite"` has a space, not a hyphen. `"Marketing & Advertising"` and `"Medical & Health"` use ampersands. `"5001+"` and `"$500k - $1M"` must match character for character. `"UK"` and `"HK"` exist as dirty values - prefer `"United Kingdom"` and `"Hong Kong"`.

**Target by company size without naming a company.** `employee_range` and `revenue_range` apply to the person's current employer, so a `search_companies` pass first is usually unnecessary:

```json
{ "seniority": "VP", "employee_range": "51-200", "country": "United States" }
```

Prefer the numeric bands over the legacy `"Small"` / `"Mid-Market"` / `"Enterprise"` / `"Unknown"` values, which carry far thinner coverage.

**Size the search before you walk it.** `search_linkedin_profile` accepts `count_only: true`, which returns the match count without fetching data or charging tokens. Every search response also carries `results.total` - read it before paginating, then increment `offset` by `limit`. Results are `_score`-ranked, so the first page is the best page.

**Emails come back in the search.** Records already include `business_email` and `business_email_risk_score` - for those rows, no follow-up enrichment call is needed.

## Step 1 - Resolve the company domain

If the user gives a company name (e.g. "HubSpot") rather than a domain:
- Infer the domain confidently for well-known companies (HubSpot to `hubspot.com`, Salesforce to `salesforce.com`, etc.)
- For unfamiliar companies, ask the user: "What's their website domain?" before proceeding

## Step 2 - Find the person

Start with `search_linkedin_profile`: pass `name` (or `first_name` + `last_name`) plus `company_domain` (preferred) or `company`. If it returns a profile, that's your match.

If it misses, fall back to `search_people` with the name in `query` plus `company_domain` (preferred) or `company`, `limit: 25`. Then scan the returned records for the target name:

- **No name match on the first page** to page deeper with `offset` (e.g. 25, 50). If still nothing with `company_domain`, retry with `company`. Tell the user what you tried.
- **Exactly one name match** to that's the person.
- **Multiple plausible matches** (e.g. same name, or first-name-only) to present all for confirmation.

## Step 3 - Present results

**One match:**
- Show: Name | Title | Company | LinkedIn URL
- If `business_email` is present in the record, note it along with its risk score - the email is already in hand. Flag it if the grade falls outside the set confirmed in Step 0 (e.g. "email on file: sam@oldco.com, risk score D - outside your accepted grades").
- Ask: "Is this the right person? I can pull their contact info if so."

**Multiple matches:**
- Present as a numbered list: Name | Title | Company | LinkedIn URL
- Ask the user to pick one before enriching

**No match after paging and retry:**
- Tell the user clearly and ask for more detail (full name, domain)

## After confirmation

Once the user confirms the right profile, hand off to the **enrich-contact** skill to retrieve email and/or phone. If `business_email` was already present in the search record, you already have it - only a separate call is needed for personal email or phone.

## Edge cases

- For `search_people`, pass the domain to `company_domain` (not `domain`) or the company name to `company`; put the person's name in `query`. You can also narrow with `seniority`/`department`/`country`/`state`/`city` filters - they cost nothing and sharply cut false matches on common names.
- If the user provides a LinkedIn URL directly, skip this skill and go to enrich-contact
- Do not invent or guess LinkedIn URLs - only surface what the tool returns
- If only a first name is provided, search with that name plus the company and present every record whose `full_name` could plausibly match; ask the user to pick
