Source people in bulk from Anysite's LinkedIn profile database (search_sql_users) with ~60 filters - derived seniority/function, company domain/id incl. past employers (alumni), career-shape (new in role, tenure, promotions), education, skills, deterministic territory buckets. Use when the user wants to find people in bulk - persona lists, buyers/candidates by role and company traits, competitor alumni, "new VP hires", recruiting searches - "найди людей", "собери список персон", "кто недавно сменил работу". For company lists first use anysite-company-sourcing; for one known person use linkedin/user; for CRM push use anysite-crm-prospect.
Instalar com Codex ou Claude Copie este prompt, cole no Codex, Claude ou outro assistente e deixe que ele revise a página da skill e instale para você.
Um comando direto ignora o prompt de revisão. Verifique a origem antes de executá-lo.
Instruções da origem · Visualização somente leitura
name
anysite-people-sourcing
description
Source people in bulk from Anysite's LinkedIn profile database (search_sql_users) with ~60 filters - derived seniority/function, company domain/id incl. past employers (alumni), career-shape (new in role, tenure, promotions), education, skills, deterministic territory buckets. Use when the user wants to find people in bulk - persona lists, buyers/candidates by role and company traits, competitor alumni, "new VP hires", recruiting searches - "найди людей", "собери список персон", "кто недавно сменил работу". For company lists first use anysite-company-sourcing; for one known person use linkedin/user; for CRM push use anysite-crm-prospect.
People Sourcing
linkedin/search/sql/users (endpoint search_sql_users) searches a very large
profile database with filters no live LinkedIn search has: derived seniority and
function, career-shape maths (tenure, promotions, months in role), past-employer
alumni, company domains and deterministic bucketing. It is the bulk people
workhorse; live search_users stays the tool for one-off lookups and namesake
disambiguation.
Verified live: filters compose correctly (seniority_min=head + function=sales +
US + 51–500 headcount + new-in-role returned exactly that, role histories fresh
to the current quarter; alumni via past_company_id returns people whose role at
that company has an end date, never current staff).
Two semantics that change how you work
An over-count result is an unbiased SAMPLE, and repeating the request
returns the SAME people (verified: two identical calls → identical 5
aliases; and raising count only appends — the list is prefix-stable, not
reshuffled). Calling again is not pagination.
Buckets are disjoint and stable (verified: bucket_total:2, index 0 vs 1
→ zero overlap across 40). Walk them for volume: bucket_total:N, bucket_index:0..N-1, also the built-in territory splitter. Ceiling:bucket_total max is 100, so the reachable population is ~100×1000 = 100k;
size bucket_total so each bucket is < 1000, otherwise a bucket is itself a
sample and you silently lose the tail.
What filters but does NOT come back (read before you "validate")
The derived fields you filter on are not in the response: no seniority,
function, profile_score, months_in_role, promotion_count, industry,
employee_count (verified on a live record). Consequences:
"Validate against intent" = read experience[] by hand: take roles with
end_date == null (the current ones) and check .position / .company.name.
You cannot re-sort or re-segment the result by seniority/function via
query_cache — those columns aren't there.
The only size field carried per role is experience[].company.employee_range,
and that string is unreliable (see Company filters). There is no trustworthy
company-size value in a people result to write to a CRM.
Filter map (grouped; full contract via discover(linkedin, search))
Text DSL (whitespace=AND, |=OR no spaces around it, "phrase", -not):
name, headline, summary, current_title, any_title (past roles
included), skills, languages, location, keywords, edu_*.
IRON RULE — quote every multi-word alternative in an OR chain. Whitespace
binds tighter than |, so an unquoted phrase SHATTERS the chain into
impossible AND groups: current_company_name: "Tencent|Tencent Games|Level Infinite|Proxima Beta" parses as (Tencent|Tencent) AND (Games|Level) AND (Infinite|Proxima) AND Beta → 0 results on Tencent-scale companies
(verified live — this exact failure burned a real user session). Correct:
"Tencent"|"Tencent Games"|"Level Infinite"|"Proxima Beta"|Krafton.
Lint before EVERY send: any token containing a space inside an OR chain
without quotes → do not send, fix first.
Derived seniority/function — start here for recall.seniority /
seniority_min (entry→ic→senior_ic→manager→head→vp→founder→cxo), function /
any_function (sales, marketing, engineering, product, data, finance, hr, ops,
legal, support, exec, …). Catch titles a text search can't (CRO, CCO, "VP
Business Development" all matched a function:sales+seniority_min:vp query —
none would survive a "vp of sales" DSL). Two traps, both measured:
seniority_min:"head" includes founder → pulls solo owners of 2-person
shops. For enterprise buyers list the levels explicitly:
seniority:["head","vp","cxo"], and always add employee_count_min.
Token false-positives: "CEO Office" (staff, not the CEO) scored ≥head;
"…President's Club 2020…" (an award on a rank-and-file AE) scored ≥vp.
Precision on a vp+sales slice was 9/10 — good, not perfect; verify the
shortlist against .
Coverage honesty
Not every profile states a current employer, industry, company size or dated
roles — those filters answer only for people who do. Set the matching has_*
flag deliberately and tell the user the trade-off ("filtering by company size
skips people whose company doesn't state one"). open_to_work: false = "no badge
observed", not "not looking". Follower/connection counts exist on a small share —
gate with has_engagement.
Two data-shape facts to expect: some profiles carry multiple concurrent open
roles (measured: 4/10 in one slice; one person had ~19 — advisory boards,
visiting posts). "Current company" is then ambiguous, and a
current_company_domain/employee_count filter may match on a quarter-time
advisory role, not the day job — so verify the target company is an operational
current role before anchoring an opener on it. And urn is occasionally null
even when alias is present — the vanity URL still enables user_find_email_by_url,
but URN-keyed handoffs (user/posts) need the live linkedin/user step first.
The loop
Start from the most selective structural filters (seniority/function/
company/country) — never bare keywords (it only helps for distinctive words
and must ride a selective filter).
Probe count:10, validate against INTENT via experience[] (structural
filters aren't semantic: "Director of Sales, 51–200, US" returned a coffee
wholesaler). Precision comes from current_company_domain[] (a list from
anysite-company-sourcing), taxonomy industry[], or headline/skills DSL.
Tighten/widen, re-probe, fetch; >1000 → size bucket_total so each bucket
< 1000 and walk it.
Free re-cuts with query_cache (only on returned fields); export with
export_data.
Zero results — debug in this order, don't flail:
Re-read your own DSL for unquoted multi-word phrases in OR chains (the #1
cause by far — see the IRON RULE).
Loosen ONE filter per step (drop profile_score_min, widen seniority,
drop industry) — never jump straight to a bare keywords full-text.
Sanity check: 0 results for a Tencent-scale employer is almost certainly a
query bug, not missing data — go back to step 1, don't report "not found".
500/408 on a broad query: don't retry as-is — narrow it (add a selective
filter) or raise timeout (≤1500). An unselective query is a scan; retrying a
scan just times out again.
Recipes
"VPs of Sales at US SaaS 50–500": seniority:["vp","cxo"], function:["sales"], country:["US"], employee_count_min:50, employee_count_max:500, industry:["Software Development"]. (SaaS ≠ a taxonomy label — narrow via the
company-side list or headline DSL. profile_score_min only if asked.)
"BD/partnerships across a brand family" (verified live, 99 profiles):
current_company_name: "\"Tencent\"|\"Tencent Games\"|\"Level Infinite\"| \"Proxima Beta\"|Krafton", current_title: "\"business development\"|bizdev| partnership|partnerships|licensing|monetization|payments|commercial", seniority:["manager","head","vp","cxo"], has_current_role:true — every
multi-word alternative quoted; regional focus goes in headline, not
country (see Geo).
"New decision-makers" (best-converting timing): add months_in_role_max:6.
"Grew up inside the company" (internal champion / stable ABM contact):
promotion_count_min:2 + avg_tenure_months_min:24.
"Competitor alumni": past_company_id:[<ids>] (+ function/seniority) — people
who LEFT. Note: this is ex-employees, NOT the competitor's customers; for
customers use anysite-crm-competitor-intel (wappalyzer + reviews).
School alumni warm-intro: edu_slug:[...] + edu_ended_year_min/max.
Recruiting: skills/edu_field DSL + avg_tenure_months_min (stability) +
n_companies_max (not a hopper) + open_to_work:true as a bonus tier only.
Territory split: same query, bucket_total:<reps>, bucket_index:<rep #>.
Handoffs and hygiene
Company lists IN (current_company_id/domain) come from
anysite-company-sourcing; people OUT go to anysite-crm-prospect
(dedup + CRM push).
For "up to N contacts across a few companies", 2–3 focused queries (base +
regional + function-specific) deduped by alias beat one mega-query — each
stays selective and each angle surfaces people the others rank low.
Emails have a real cost and yield — don't hand-wave it. The result's
alias is the vanity URL, ready for the email cascade (anysite-mcp →
Email finding): user_email first (cheap, ~half personal addresses, low
yield), then user_find_email_by_url (~75% yield but 50cr each — estimate
50cr × N and confirm before a big run) with its valid_email/email_status
as the deliverability gate. Personal/unverified addresses never go into a work
sequence. There is no built-in email verifier — for bounce-critical sends, gate
externally.
Live-verify the outreach shortlist via linkedin/user — the DB is fresh
but not realtime; it also yields the vanity URL. Job-change detection on CRM
contacts belongs to anysite-crm-champions (this DB's months_since_change_max
is its cheap pre-filter, not its evidence).
Sourcing individuals is personal-data processing: search to the stated business
need, don't hoard.
experience[]
Company — a ladder, pick the rung deliberately:
current_company_name DSL with QUOTED brand variants — the default. A bare
token like Tencent also matches subsidiaries ("Tencent Korea", "Fintech at
Tencent") — a feature for brand families, a bug if you need one legal entity.
current_company_id[] (numeric LinkedIn page ids, resolve via company
search first) — when strictness matters: separating Level Infinite from the
rest of Tencent, excluding brand-name lookalikes.
current_company_domain[] (bare domains) — when domains are what you have
(e.g. a CRM list).
keywords — LAST resort, only WITH ≥1 selective filter (company/title/
seniority/country) and never as the employer filter itself: it's full-text
across all fields, and an unselective keywords query is a DB scan
(measured: 140s → HTTP 500).
Also: any_company_id/domain (ever worked);
past_company_id[] (worked and LEFT — alumni); employee_count_min/max of
the current company. Do NOT use employee_range[] — the band string
contradicts the true headcount often (measured ~35%: a 104-person company
banded "11-50", a 58-person one "501-1000"); filter size only with the numeric
employee_count_min/max.
Industry:industry[] / any_industry[] take exact LinkedIn-taxonomy
labels (e.g. "Software Development" works), NOT market words — ["fintech"]
returns 0 (measured). Resolve labels via search_industries; for "fintech",
"SaaS" and the like, filter on the company side (anysite-company-sourcing
specialities) or on headline/skills DSL instead.
Geo:country[] ISO2 (reliable); location DSL for cities/metros.
"Responsible for a market" ≠ "located in it." When the user wants people
FOCUSED on a region (CIS/MENA/emerging markets), do NOT filter country by
that region — BD/publishing teams of global companies sit in HQ (KR/CN/US/NL/
SG). Search the market mention in the profile instead:
headline/summary: CIS|Russia|Kazakhstan|MENA|"emerging markets"|"Middle East". Measured on a live case: country:[RU,KZ,UZ,AE,SA,…] → 2 profiles;
the headline variant → 84. Use country only when the person must physically
BE in the region — and warn the user the pool will be narrow.
Education:edu_slug[], edu_institution, edu_field,
edu_ended_year_min/max (graduation cohort ≈ age proxy).
Career shape:months_in_role_max (new in role), months_in_role_min,
months_since_change_max (started OR ended a role recently — job-change
radar), experience_years_min, n_roles_*, n_companies_* (stability vs
hopping), promotion_count_min (promoted without changing employer),
avg_tenure_months_*.
Quality & coverage:profile_score_min (0–8) — do NOT set it by default:
it silently drops sparse-but-on-target profiles (a real user's default of 5
cut exactly the people they were hunting). Add it only when the user asks for
"complete/outreach-grade profiles" (then 5+), or as a tie-breaker on an
over-1000 pool. Plus the has_* family (has_current_role, has_role_dates,
has_education, has_company_size, has_engagement…).
Badges/engagement:open_to_work, hiring, verified, is_premium,
is_top_voice, follower_count_min, connection_count_min. (is_creator /
is_influencer filter but are NOT returned — you can't confirm them.)
Lookalike (EXPERIMENTAL — verify every time):similar_to / also_viewed
by alias. Measured unreliable: two seeds returned namesakes (same name,
different people) or nothing — NOT semantic lookalikes. Do not use it as a
"people like our champion" shortcut; if you try it, probe count:5 and confirm
the surnames differ from the seed's before trusting a single row. For real
lookalikes, replicate the champion's attributes as explicit filters instead.
Freshness:fetched_after (unix ts) — only recently refreshed profiles.