Find recruiting firm
Skill jeremylongshore/claude-code-plugins-plus-skills/plugins/mcp/servicegraph/skills/find-recruiting-firm
Use whenever the user wants to find, shortlist, vet, or enrich US recruiting and staffing firms — executive search/retained search, RPO, tech/sales/healthcare recruiting, contingent/contract staffing, and temp staffing. Triggers on "find me an executive search firm for a CFO search", "shortlist three retained-search boutiques in NY focused on tech", "we need RPO support for a 50-engineer hiring push", or "pull contact info for these 8 staffing firm domains", even when described indirectly (need help hiring at scale, executive recruiter for senior roles). Drives the ServiceGraph API (api.servicegraph.co) — a 100k+ US firm catalog filterable by industry, services, location, size, ratings. Skip when the user wants to hire someone as their own employee (job-board questions, in-house recruiter hires, "where should I post the role"), individual job-seekers looking for recruiters to represent them, candidate-side career coaching, non-US firms, individual freelance recruiters.From its SKILL.md
npx -y skills add jeremylongshore/claude-code-plugins-plus-skills --skill find-recruiting-firmAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
What its file declares
Copied from the file, not written here
The file declares its own license as MIT. That is the author’s claim about this one file, and it is not the same thing as the license GitHub reports for the repository, which is listed with the other numbers below.
SKILL.md
13.4 KB, ~3.3k tokens by cl100k_base, as published. Nobody here has run it
find-recruiting-firm
Overview
Drive the ServiceGraph API (https://api.servicegraph.co) to find,
shortlist, and enrich US recruiting and staffing firms via the
pro_services dataset.
This skill is for procuring an external recruiting/staffing firm to do hiring on the user's behalf. It is NOT for:
- recruiting an in-house employee (the user wants to hire someone for their own team — that's job-posting, not procurement),
- candidate-side asks (an individual job-seeker looking for someone to represent them).
Both share keyword overlap with the positive case ("recruiter", "hire"), so the boundary matters.
Always pin industry:hr_recruiting_staffing. Sub-types
(executive search, RPO, contingent staffing, temp, vertical
specializations) are NOT separate tags — sub-type specialization is
a keyword substring search on firm text.
Any HTTP client works (curl, fetch, requests). Examples below use curl.
When NOT to use this skill
- "I want to hire a [role] for my team — where should I post the job?" → recruiting-an-employee.
- "Find me a recruiter to represent me in my job search" → candidate side.
- "Hire an in-house recruiter / Head of Talent" → recruiting an employee.
- "Help me write a job description" → DIY/do-the-work.
- ATS or HR-software comparisons (Greenhouse vs Lever, Workday).
- Career coaching for individual job-seekers.
- Non-US firms / individual freelance recruiters.
Prerequisites
- ServiceGraph access, either:
- the ServiceGraph MCP server (
https://mcp.servicegraph.co) loaded in your harness — this plugin's.mcp.jsonwires it up; OAuth 2.1 + PKCE keeps credentials in the harness sandbox — or - a ServiceGraph API key (
vk_…, minted at https://servicegraph.co/profile/api-keys) available asSERVICEGRAPH_API_KEYin the environment or.env.localfor the REST path (setup steps under Auth below).
- the ServiceGraph MCP server (
- An HTTP client for the REST path — the examples use
curl.
Instructions
The loop is free-first: discovery, validation, search, and brief reads cost nothing; only unlock after the user confirms the spend.
- Pick the call path — the ServiceGraph MCP tools if loaded, otherwise the REST flow (MCP server and Auth sections below).
GET /v1/datasets/pro_services/fields?include_values=1— confirm the fields and values you plan to filter on exist.- Build the filter (Filter DSL below) and validate it with
GET /v1/datasets/pro_services/check— or draft it from plain English viaPOST /v1/datasets/pro_services/translate-intent. GET /v1/datasets/pro_services/search— present the free brief cards and let the user pick.- Quote the unlock cost (10 credits per row, 30-day TTL) and get an explicit go-ahead.
POST /v1/datasets/pro_services/unlockswith the chosen apexes; report the revealed detail.GET /v1/me/creditsto report the remaining balance when asked.
MCP server (preferred for authed calls)
If your harness has the ServiceGraph MCP server loaded (tools
containing servicegraph), prefer those — OAuth 2.1 + PKCE keeps the
token in the harness sandbox. Otherwise use the REST flow below.
API surface (dataset id: pro_services)
Every endpoint requires the bearer (Authorization: Bearer vk_…).
No anonymous tier.
| Endpoint | Cost | Use it for |
|---|---|---|
GET /v1/datasets/pro_services/fields[?include_values=1] | free | Confirm hr_recruiting_staffing is in the industry value list. |
GET /v1/datasets/pro_services/check?filter=… | free | Validate filter. |
POST /v1/datasets/pro_services/translate-intent | free | {intent} → DSL filter + sanity count. |
GET /v1/datasets/pro_services/search?filter=…&limit= | free | Brief firm cards + per-row unlock hint + total. |
GET /v1/datasets/pro_services/:apex | free | One row brief; detail only if unlocked. |
POST /v1/datasets/pro_services/unlocks | 10 credits / firm | {apexes:[...]} ≤100; atomic; 30-day TTL on detail. |
GET /v1/me/credits | free | Balance. |
Cost model. Discovery / validation / search / brief reads are
free. Detail (url, phone, email, social, address, full platforms
map) costs 10 credits per firm and lasts 30 days.
Auth
vk_* API keys minted in the dashboard. Keep the token out of the
LLM context — never read .env* into your context; dispatch via
shell.
-
Try the call first through a shell wrapper that sources
.env.local:( set -a; [ -f .env.local ] && . ./.env.local; set +a; curl -sS -H "Authorization: Bearer $SERVICEGRAPH_API_KEY" \ 'https://api.servicegraph.co/v1/datasets/pro_services/fields' ) -
On
401prompt the user:"Open https://servicegraph.co/profile/api-keys, create a key, and add
SERVICEGRAPH_API_KEY=vk_…to.env.localhere (or export it). Tell me when done. Please don't paste the key into chat." -
Retry after the user signals ready.
Filter DSL
GitHub-search-style.
filter := orExpr
orExpr := andExpr ("OR" andExpr)*
andExpr := notExpr (("AND")? notExpr)* # whitespace = implicit AND
notExpr := ("NOT" | "-") notExpr | atom
atom := "(" filter ")" | predicate
predicate:= IDENT op valueOrList | bareword
op := ":" | "=" | ">=" | "<=" | ">" | "<"
valueOrList := value ("," value)*
value := IDENT | NUMBER | tagAtEvidence
tagAtEvidence := IDENT "@" ("low"|"medium"|"high")
bareword := IDENT | NUMBER # → keyword:<bareword>
Four rules that bite: AND binds tighter than OR (use parens);
comma list = OR within one predicate; negation is -x or NOT x;
bareword = keyword search (quote multi-word phrases).
Recruiting-flavored examples (validate yours with /check):
industry:hr_recruiting_staffing "executive search"
industry:hr_recruiting_staffing "retained search" state:NY tech
industry:hr_recruiting_staffing rpo state:CA
industry:hr_recruiting_staffing contingent staffing
industry:hr_recruiting_staffing healthcare state:TX,FL
industry:hr_recruiting_staffing sales saas
industry:hr_recruiting_staffing rating>=4 has:clutch
Sub-type → keyword mapping:
| User asks for | Add as keyword(s) |
|---|---|
| Executive search / retained search | executive, retained |
| RPO (recruitment process outsourcing) | rpo, "recruitment process outsourcing" |
| Contingent / contract staffing | contingent, contract |
| Temp / temporary staffing | temp, temporary |
| Tech recruiting | tech, technical, engineering |
| Sales recruiting | sales |
| Healthcare recruiting | healthcare, clinical, nursing |
| Finance / accounting recruiting | finance, accounting |
| Legal recruiting | legal, attorney |
Identifying firms — apex
Firms are identified by their apex domain (korn-ferry.com, not
www.korn-ferry.com/about).
Output
All responses are JSON.
- Search returns free brief firm cards —
apex,name, location, and rating signals — plus a per-row unlock hint and the matchtotal. Briefs never includeurl,phone_primary,email_primary,legal_name,address_full, or the fullplatformsmap. - Unlock (
POST …/unlocks) returns each unlocked firm's detail block — contact fields, address, socials, theplatformsmap — plus per-item billing; detail stays readable for 30 days. - Errors arrive as a JSON envelope
{"error": {"code": "…", "message": "…"}}— see Errors below.
Examples
A. Executive search for a CFO
GET /v1/datasets/pro_services/search?filter=industry:hr_recruiting_staffing+executive+search&limit=10
# Present, get pick of 3. "Unlocking 3 = 30 credits, 30-day TTL."
POST /v1/datasets/pro_services/unlocks
{ "apexes": ["firm-a.com", "firm-b.com", "firm-c.com"] }
B. Retained boutique in a state, vertical
GET /v1/datasets/pro_services/search?filter=industry:hr_recruiting_staffing+retained+state:NY+tech+-company_size_signal:large_50plus&limit=10
C. RPO for a hiring surge
GET /v1/datasets/pro_services/search?filter=industry:hr_recruiting_staffing+rpo+(tech OR engineering)&limit=10
D. Indirect intent — "scaling fast, need help hiring"
GET /v1/datasets/pro_services/search?filter=industry:hr_recruiting_staffing+(rpo OR contingent)&limit=10
Or use the translator:
POST /v1/datasets/pro_services/translate-intent
{ "intent": "RPO or volume recruiting partner for a 50-engineer hiring push" }
E. Vertical: healthcare staffing
GET /v1/datasets/pro_services/search?filter=industry:hr_recruiting_staffing+healthcare+state:OH,IL,MI,IN,WI,MN&limit=10
F. Quality threshold + tech-sector
GET /v1/datasets/pro_services/search?filter=industry:hr_recruiting_staffing+executive+search+tech+rating>=4&limit=10
G. BYO apex list — enrich domains
User pastes 8–20 staffing/recruiting firm domains:
GET /v1/datasets/pro_services/:apexper domain — free brief (404 = not in catalog, no charge).- User picks N to fully enrich.
POST /unlocks= 10×N credits, atomic, detail returned. - Re-runs within 30-day TTL are free.
Gotchas
- Always pin
industry:hr_recruiting_staffing. Without it, "recruiter" / "executive search" keywords leak into other industries. - Distinguish "find me a recruiting firm" (procurement, fires) from "find me a recruiter / hire a recruiter for our team" (recruiting-an-employee, refuses). When ambiguous, lean on context: explicit firm/agency/RPO language or volume framing → procurement; "for our team" / "to post the job" / "I want to hire" → in-house hire.
- Candidate-side asks ("represent me as a candidate", "find me a job") are out of scope.
- Career coaching for individuals is a different need (and shares the
executive-coachingkeyword with management consulting). Refuse — this skill is firm-procurement. - Sub-types are keyword-only. Multi-word sub-types split into ANDed barewords unless quoted (
"executive search"→ one phrase). - Briefs DO include
apex,name, location, ratings. They DON'T includeurl,phone_primary,email_primary,legal_name,address_full, fullplatforms— those require an unlock. not_found/not_in_dataset404 = not inpro_services. Skip; not charged.- Unlock is atomic. N apexes either all charge (up to 10×N credits) or none on 402.
- Within-TTL re-views are free (
was_cached:true).
Errors
JSON envelope: {"error": {"code": "...", "message": "..."}}.
| Status | Code | What to do |
|---|---|---|
| 400 | filter_parse_error | position included; fix and re-validate with /check. |
| 400 | kind_in_filter | Strip any kind: from filter. |
| 400 | field_not_in_dataset | Drop the disallowed field. |
| 400 | invalid_apex | Re-normalize. |
| 401 | unauthorized / invalid_audience | Re-prompt for fresh vk_…. |
| 402 | insufficient_credits | needed and balance; nothing charged. |
| 404 | not_found / not_in_dataset | Skip; not charged. |
| 429 | rate_limited | Honor Retry-After. |
End-to-end example
User: "Three retained executive search firms in NY focused on tech CFOs, ideally with 4-star ratings and a Clutch profile."
GET /v1/datasets/pro_services/fields?include_values=1
GET /v1/datasets/pro_services/check?filter=industry:hr_recruiting_staffing+retained+executive+state:NY+tech+rating>=4+has:clutch
GET /v1/datasets/pro_services/search?filter=...&limit=10
# Present briefs. "Unlocking 3 = 30 credits, 30-day TTL."
POST /v1/datasets/pro_services/unlocks
{ "apexes": ["firm-a.com", "firm-b.com", "firm-c.com"] }
GET /v1/me/credits
Resources
- Upstream source: https://github.com/nostrband/ServiceGraph
- ServiceGraph API: https://api.servicegraph.co — keys at https://servicegraph.co/profile/api-keys
- Hub skill:
servicegraph(this plugin) — the dataset-agnostic entry point when the user names ServiceGraph explicitly.
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.
Gives 0 of the 12 instructions most hr recruiting skills give in ~3.3k tokens
Counted across 356 of the 357 authors here whose files we hold, read 2026-08-07
- Quantify achievements with specific metricsin 14 of 356, across 6 files
- Keep the resume under two pagesin 14 of 356, across 6 files
- Request the full job description if not providedin 12 of 356, across 4 files
- Extract keywords and prioritize job requirementsin 12 of 356, across 4 files
- Stop and ask for clarification if required inputs are missingin 12 of 356, across 5 files
- Map candidate experience to job requirementsin 11 of 356, across 3 files
- Ask if the user wants adjustmentsin 11 of 356, across 3 files
- Provide strengths and gap analysis after the resumein 10 of 356, across 2 files
- Request candidate background details if not providedin 10 of 356, across 2 files
- Format experience bullets as action verb plus resultin 10 of 356, across 2 files
- Ask for missing inputs before startingin 10 of 356, across 9 files
- Use exact job description terminologyin 9 of 356, across 1 file
Said here and by no other author read
- confirm fields and values before filtering
- validate filters using the check endpoint
- present free brief cards to the user
- quote unlock cost and get explicit approval
- post chosen apexes to the unlocks endpoint
- report the remaining balance when asked
Grouped from the skills themselves: near-identical wordings counted once, and counted by distinct author, so one author publishing three of these counts once. Length counted with cl100k_base; the agent that loads this file may tokenize it differently.