Your GTM belongs in gitRegister
Cookbooks

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.

Installation
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.
Paste it into Claude Code, Cursor, Codex, Gemini CLI, Devin or Replicas.

Say 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)StatusWhat 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_icpNothing: a consumer app, a disqualifier in the ICP
Ana Costa (Director of RevOps)Litwareno_domainNothing: 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 #

InputWhy
marketLooked upIt 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_sizeLooked upAbove 2,500 a single URL silently stops at 2,500 and the rest of the market is never seen
slack_channelAskedA channel nobody owns is a channel nobody reads, and a wrong id posts somewhere else or nowhere
cadenceAskedEvery 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
crmLooked upThe 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 posted run is shown with its Slack message
  • a not_icp run 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.mjs passes 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 #

ResourceKindPurpose
new_hiresModelThe Sales Navigator job-change search, one row per person
new_hire_icp_qualifierAgentJudges the company against context/icp.md
route_new_hiresPlayQualifies each added person and posts the ones that fit
linkedin, sales_navigator, anthropic, slackConnectorsBound to the workspace defaults; nothing is created

Placeholders (edit before deploy) #

PlaceholderFileResolved from
PLACEHOLDER_SLACK_CHANNEL_IDinfra/plays/route-new-hires.tsThe Slack connector’s channel autocomplete
the search objectinfra/models/new-hires.tsThe ICP, and the Sales Navigator autocompletes
languageModelinfra/agents/icp-qualifier.tsThe model the team runs its agents on
icp.mdthis skill’s context/icp.mdThe 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:

shellscript
node --import tsx evals/contract.mjs

From the project root:

shellscript
cargo-ai cdk types && cargo-ai cdk check && cargo-ai cdk plan

Give your agents a runtime

Bring the agents you have.Start free, deploy in one command.