New hire detection
Watch your whole market for people who just took a role you sell to, qualify the company each one joined against your ICP, and post the ones that fit to Slack with the verdict and the links. A deployed pipeline on a Sales Navigator job-change search; checking or writing the CRM is an optional variation.
Set up the new-hire-detection cookbook in this project.
1. If the Cargo CLI is not installed yet, follow every step in https://api.getcargo.io/INSTALL.md
2. From the Cargo project, run: cargo-ai cdk add cookbook/new-hire-detection
3. Then follow .claude/skills/new-hire-detection/SKILL.md. Stop for my approval before any paid call, and stop at "cargo-ai project plan" before deploying anything.$cargo-ai cdk add cookbook/new-hire-detectionSay this to your agent
Every time a new VP Sales or head of RevOps starts at a US software company with 51 to 500 people, post it in #new-hires.
Illustrative output #
Fictional records, to show the shape of what comes back.
| Person (role) | Company (domain) | Status | What landed in Slack |
|---|---|---|---|
| Priya Raman (VP Sales) | Northwind (northwind.example) | posted | ”New VP Sales at Northwind (Tier 1, 88/100)”, the rationale, both links |
| Mei Lin (Chief Revenue Officer) | Contoso (contoso.example) | posted | ”New Chief Revenue Officer at Contoso (Tier 1, 84/100)”, the rationale |
| Tomás Ortega (Head of RevOps) | Fabrikam (fabrikam.example) | posted | ”New Head of RevOps at Fabrikam (Tier 2, 71/100)”, the rationale |
| Sam Hale (VP Sales) | Tailspin (tailspin.example) | not_icp | Nothing: a consumer app, a disqualifier in the ICP |
| Ana Costa (Director of RevOps) | Litware | no_domain | Nothing: the company page has no website, so there was nothing to qualify on |
Five new hires in one sync: three posted, one declined by the qualifier, one stopped at the domain guard before any qualifier call.
What you will be asked #
| Input | Why | |
|---|---|---|
| market | Looked up | It is the audience. The qualifier reads the same ICP, so a market that lives only in a URL leaves the agent judging against nothing |
| search_size | Looked up | Above 2,500 a single URL silently stops at 2,500 and the rest of the market is never seen |
| slack_channel | Asked | A channel nobody owns is a channel nobody reads, and a wrong id posts somewhere else or nowhere |
| cadence | Asked | Every sync re-extracts and re-bills the whole search, so cadence is the main cost dial, traded against how fresh a new hire is when the team hears about it |
| crm | Looked up | The template needs no CRM; a team that has one usually wants at least to know whether the company is already in it |
Done when #
- each deployed search URL was counted with
searchPersonMetrics, sits under 2,500, and keeps the three job-change filters - the pilot synced ten rows whose columns match the workflow input
- every run in the pilot ended in a named status, and every
postedrun is shown with its Slack message - a
not_icprun shows the qualifier’s rationale, and posted nothing - every post landed in the channel the operator named, and nowhere else
node --import tsx evals/contract.mjspasses against the adapted resources- after opening up, the next sync created runs only for people new since the previous one
What it costs #
Fetch live prices before every estimate: cargo-ai connection integration get salesNavigator,
linkedin, and the LLM connector’s model. Quote the lookup time with the estimate.
Extraction is the main spend, and it repeats. fetchLeadSearch bills per extracted lead, and
it is not incremental: every sync extracts the whole search again, including the people already in
the model. “Changed jobs” spans roughly the last 90 days, so a sync every two weeks re-pays for most
of the previous sync to find the ones who are new. One sync costs the counted search (capped at
limit per URL) times the per-lead price; a month costs that times the number of syncs.
Qualifying is per new person, and only new people. Each run pays one company enrichment, and
each company with a domain adds one qualifier call. The Slack post carries no per-call price of its
own. The CRM variations add their own lookups and, on crm_routing, an email lookup per person.
Counting is cheap and comes first. One searchPersonMetrics call per candidate URL tells you
what a sync will extract before anything is extracted.
A Sales Navigator job-change search over your market, and one play that qualifies the company each
new person joined and posts the ones that fit to Slack. This file explains why the design is the way
it is; SKILL.md is the procedure.
flowchart TD
search["Sales Navigator search<br/>titles x industry x headcount x region<br/>+ changed jobs, under a year in role"] --> added["New person in the model"]
added --> enrich["Enrich the company<br/>LinkedIn"]
enrich --> domain{"Domain?"}
domain -->|no| stop1["Stop: no_domain"]
domain -->|yes| qualify["Qualifier agent<br/>reads context/icp.md"]
qualify --> gate{"ICP?"}
gate -->|no| stop2["Stop: not_icp"]
gate -->|yes| post["Slack post<br/>person, company, verdict, links"]
Resources #
| Resource | Kind | Purpose |
|---|---|---|
new_hires | Model | The Sales Navigator job-change search, one row per person |
new_hire_icp_qualifier | Agent | Judges the company against context/icp.md |
route_new_hires | Play | Qualifies each added person and posts the ones that fit |
linkedin, sales_navigator, anthropic, slack | Connectors | Bound to the workspace defaults; nothing is created |
Placeholders (edit before deploy) #
| Placeholder | File | Resolved from |
|---|---|---|
PLACEHOLDER_SLACK_CHANNEL_ID | infra/plays/route-new-hires.ts | The Slack connector’s channel autocomplete |
the search object | infra/models/new-hires.ts | The ICP, and the Sales Navigator autocompletes |
languageModel | infra/agents/icp-qualifier.ts | The model the team runs its agents on |
icp.md | this skill’s context/icp.md | The team’s ICP, copied into the project’s context/ |
Why it is built this way #
The market, not the book. The model starts from everyone who just took a target role in a
market slice, not from contacts you already hold. That is the difference from track-job-changes,
which asks whether your own people moved.
Slack, not the CRM, by default. A Slack post needs one channel id. Writing into a CRM needs owner
IDs, a CSM field, association types, a LinkedIn field, a routing signal someone maintains, and a
dedupe policy for people who moved, and every mistake stays in the CRM. Most teams want the signal
first and decide what to do with it after reading it. The CRM is one step away when they want it:
a read-only “already in the CRM” line (crm_lookup), or the CRM as the destination with routed
tasks (crm_routing), both in references/crm-adaptation.md.
Enrich, guard, then judge. A Sales Navigator lead carries a company URL. The company is enriched first, so the qualifier judges a description, specialties and a headcount rather than a name, and a company with no website stops there.
Qualification as a gate. The qualifier returns a verdict and a branch acts on it, so a company the ICP rejects is never posted. An agent rather than a headcount filter, because it reads the description and specialties and can apply exclusions no number can: competitors, agencies, holding companies. It reads the ICP from the workspace context, the same file the search was shaped from, so the two cannot drift apart.
One locked channel. The channel id is a constant in the play, not computed and not chosen by an agent, so a prospect’s name never lands in a channel shared with a customer.
It stops at the post. Nothing is drafted or sent to the person. Someone reads the post and decides, and the team’s own sequencer does the sending.
The schedule is a cost decision. The extractor re-buys the whole search on every sync, and
changeKinds: ["added"] makes only the new people create runs. The model ships with no schedule;
every two weeks is the default added when opening up, the trade between spend and how fresh a new
hire is when the team hears about it.
Verify #
From this skill’s folder:
node --import tsx evals/contract.mjs
From the project root:
cargo-ai cdk types && cargo-ai cdk check && cargo-ai cdk plan