# Source and screen candidates (/use-cases/industry-specialized/recruiting-sourcing)



Copy this prompt to start your first task:

<Prompt>
  We're hiring a backend engineer. Score incoming resumes against the JD, sort them into recommended, backup, and pass lists with reasoning for each, and draft a few targeted interview questions for the top candidates so I can move fast on scheduling.
</Prompt>

<LivePreview component="NewThread" scenario="{ draft: &#x22;We're hiring a backend engineer. Score incoming resumes against the JD, sort them into recommended, backup, and pass lists with reasoning for each, and draft a few targeted interview questions for the top candidates so I can move fast on scheduling.&#x22; }" />

## What is this workflow? [#what-is-this-workflow]

"Source and screen candidates" is a recurring headhunting job: instead of taking the JD at face value, the workflow starts by pushing back on vague terms like "senior" and asking what they actually mean for this team. It then searches for passive candidates who fit that real bar, not just people who already applied, and drafts a personalized outreach message for each one, referencing something specific from their actual background rather than a mail-merge template. The result is a shortlist with reasoning attached, recalibrated whenever the bar turns out to be wrong, on a pipeline that keeps moving on its own.

<Callout type="warn">
  This screens and ranks. It doesn't reject on your behalf, and it doesn't send outreach without you seeing it first. Every "no" it proposes should get a human glance before a candidate hears anything, both because judgment calls this close deserve a second read and because hiring decisions carry real legal exposure if the criteria weren't applied consistently. Treat the ranked list and the drafted outreach as strong first drafts, not an autopilot.
</Callout>

## How to use this workflow [#how-to-use-this-workflow]

<Steps>
  <Step>
    ### Hire an HR teammate, then write the bio to match this job, not the generic template [#hire-an-hr-teammate-then-write-the-bio-to-match-this-job-not-the-generic-template]

    Open **AI Teammates** in the sidebar, click **Hire AI Teammate**, and pick the **HR Manager** template. The template's default bio is generic HR admin. Replace it on the Profile step so the teammate starts out already knowing this is a sourcing role, not just ticket triage:

    <Prompt>
      You're our technical recruiter. Before sourcing, push back on vague JD terms like 'senior': ask what they actually mean for this team. Search for passive candidates who fit the real bar, not just inbound applicants, and personalize outreach to each person's actual background, never a generic template. Hold every outreach draft and rejection for my review before anything goes out. Screen inbound applicants against the same bar as sourced candidates.
    </Prompt>

    Confirm the name and click **Create teammate**. They land in their own channel, which is where you'll send everything below. [More on hiring →](/ai-teammates/hire-an-ai-teammate)

    <LivePreview component="CreateAssistantPage" scenario="{ focus: &#x22;profile&#x22;, initialState: { start: &#x22;template&#x22;, templateRef: &#x22;@helio/hr-manager&#x22;, name: &#x22;HR Manager&#x22;, bio: &#x22;You're our technical recruiter. Before sourcing, push back on vague JD terms like 'senior': ask what they actually mean for this team. Search for passive candidates who fit the real bar, not just inbound applicants, and personalize outreach to each person's actual background, never a generic template. Hold every outreach draft and rejection for my review before anything goes out. Screen inbound applicants against the same bar as sourced candidates.&#x22; } }" />
  </Step>

  <Step>
    ### Connect where candidates actually are [#connect-where-candidates-actually-are]

    LinkedIn is where the candidates are; a shared sheet or Notion holds the pipeline itself. [Connect your tools →](/connect/connect-tools-to-ai-teammates)

    Worth understanding before relying on it: the native LinkedIn connector under Integrations signs the teammate in as your own account, mainly for identity and, eventually, posting as you. It carries no scope for searching, browsing other people's profiles, or messaging. Candidate search and outreach run through something else entirely, a real cloud browser session the teammate drives directly, the same way a person clicking around LinkedIn would.

    <LivePreview component="AssistantIntegrations" />
  </Step>

  <Step>
    ### When LinkedIn asks for a human, hand off the browser session [#when-linkedin-asks-for-a-human-hand-off-the-browser-session]

    That browser session hits the same login wall, and often the same two-factor prompt, a person would. The teammate can't enter a 2FA code on its own, so instead of stalling it shares the live session link in chat and asks you to sign in there yourself.

    <Prompt>
      Search LinkedIn for [role] who've actually [done the specific thing that matters for this job], not just held the title.
    </Prompt>

    <LivePreview
      component="AssistantChat"
      scenario="{ assistantName: &#x22;HR Manager&#x22;, messages: [
    { author: &#x22;user&#x22;, text: &#x22;Search LinkedIn for backend engineers who've owned a distributed system in production, not just held the title.&#x22; },
    { author: &#x22;assistant&#x22;, text: &#x22;Opening a browser session for this search. LinkedIn wants a sign-in, and it's asking for a two-factor code I can't enter myself. Here's the live session: [session link], log in there in your own tab the way you normally would, and let me know once you're through. I'll pick the search back up in that same session.&#x22; },
    { author: &#x22;user&#x22;, text: &#x22;Done, I'm in.&#x22; },
    { author: &#x22;assistant&#x22;, text: &#x22;Picking it back up now, checking the page to confirm the login went through before I start searching.&#x22; },
  ] }"
    />

    <Callout type="info">
      This is a shared session, not an isolated hand-off: while that link is open, the teammate has the same access to the browser it had before you logged in, same window, not a copy. It never types your password or 2FA code itself, that part really is you, typing into your own browser tab, but don't leave the session sitting open longer than the login takes.
    </Callout>
  </Step>

  <Step>
    ### Don't source against the JD as written: get it to push back first [#dont-source-against-the-jd-as-written-get-it-to-push-back-first]

    A JD handed down from a hiring manager is almost always generic. Pasting it in and asking for candidates just launders that vagueness into a search. Ask for the gaps instead:

    <Prompt>
      We're opening a [role] role. Here's the JD [attached]. Before you source anyone, tell me what's underspecified in it that would actually change who you search for.
    </Prompt>

    <LivePreview
      component="AssistantChat"
      scenario="{ assistantName: &#x22;HR Manager&#x22;, messages: [
    { author: &#x22;user&#x22;, text: &#x22;We're opening a senior backend engineer role. Here's the JD [attached]. Before you source anyone, tell me what's underspecified in it that would actually change who you search for.&#x22; },
    { author: &#x22;assistant&#x22;, text: &#x22;Three things this JD doesn't answer, and each one changes the search: (1) \&#x22;Senior\&#x22;: does that mean owned a service end to end, or just held the title? Changes whether I search for scope of ownership or years. (2) \&#x22;Distributed systems experience\&#x22;: greenfield build, or operating an existing system under load? Very different candidate pools. (3) \&#x22;Remote OK\&#x22;: genuinely open, or a soft preference for the same time zone that becomes friction at offer stage? I'd rather ask now than source 15 people against the wrong read.&#x22; },
  ] }"
    />
  </Step>

  <Step>
    ### Search for people who aren't applying, and write to them like you read their profile [#search-for-people-who-arent-applying-and-write-to-them-like-you-read-their-profile]

    With the real bar in hand, the actual headhunting step is finding passive candidates and drafting outreach specific enough that it doesn't read as a template:

    <Prompt>
      Good questions — [answers to what you flagged, e.g. what "senior" actually means, what the key skill really requires, whether remote is genuinely open]. Search LinkedIn for 10-15 people who fit that, not just applicants. For each one, draft a short outreach message that references something specific from their actual background, not a generic 'impressive profile' opener.
    </Prompt>

    <LivePreview
      component="AssistantChat"
      scenario="{ assistantName: &#x22;HR Manager&#x22;, messages: [
    { author: &#x22;user&#x22;, text: &#x22;Good questions. Senior means owned a service end to end, distributed systems means operated one under real load, and remote is genuinely open. Search LinkedIn for 10-15 people who fit that, not just applicants. For each one, draft a short outreach message that references something specific from their actual background, not a generic 'impressive profile' opener.&#x22; },
    { author: &#x22;assistant&#x22;, text: &#x22;Searching against ownership and production-load experience, not just the job title. For example, one candidate's profile mentions migrating a queue system through a 10x traffic spike, so the opener references that specific migration, not \&#x22;your impressive background.\&#x22; Holding all 10-15 drafts for your review before anything sends; none of these go out without you seeing the exact wording first.&#x22; },
  ] }"
    />
  </Step>

  <Step>
    ### Recalibrate when the bar turns out wrong [#recalibrate-when-the-bar-turns-out-wrong]

    The bar from the intake step is still a guess until real candidates test it. When a hiring manager pushes back (too many candidates passing, or the "senior" bar is filtering out people who'd actually be fine), say so directly instead of quietly living with a pipeline that doesn't match what the team needs:

    <Prompt>
      The hiring manager says our last [N] "strong fits" weren't right for what she actually needs — [what was off, e.g. too junior, wrong specialization]. She wants someone who [the real bar]. Re-screen the current pipeline against that bar, and tell me who moves and who drops.
    </Prompt>

    <LivePreview
      component="AssistantChat"
      scenario="{ assistantName: &#x22;HR Manager&#x22;, messages: [
    { author: &#x22;user&#x22;, text: &#x22;The hiring manager says our last 3 'strong fits' were too junior for what she actually needs. She wants someone who's owned a service in production, not just contributed to one. Re-screen the current pipeline against that bar, and tell me who moves and who drops.&#x22; },
    { author: &#x22;assistant&#x22;, text: &#x22;Re-screening against ownership, not contribution. Of the 3 she flagged: 2 drop under the new bar (contributed to a team-owned service, didn't own one end to end), 1 stays (owned an on-call rotation for a payments service; that just wasn't clear from the original resume, I should have caught it the first pass). Updating the pipeline sheet and re-ranking the rest now.&#x22; },
  ] }"
    />
  </Step>

  <Step>
    ### Keep the pipeline moving [#keep-the-pipeline-moving]

    The daily summary lands in `#hiring`, and a teammate can only post in channels it's a member of — add this teammate to `#hiring` first. Then open **Automations** in the sidebar, click the **Create via Chat** dropdown, and pick this teammate. This is where inbound applicants get folded in, screened against the same bar the outreach candidates were, not a separate lower bar just because they came to you first:

    <Prompt>
      Every morning, check for new inbound applicants and outreach replies. Screen new applicants against the same bar we set for this role; don't hold them to a looser standard just because they applied instead of being sourced. Update the pipeline sheet and post a one-line summary to #hiring: who's new, who moved stages, who needs a reply from me.
    </Prompt>

    <LivePreview component="NewThread" scenario="{ populated: false }" />
  </Step>
</Steps>

## What You Need to Know [#what-you-need-to-know]

**This flow pauses for your review before anything leaves Helio:** sending outreach and proposing a rejection are exactly the sensitive, hard-to-undo actions that wait for sign-off — the teammate holds every outreach draft and rejection for you to approve before a candidate sees or hears anything. Screening, ranking, and drafting run on their own. See [Control](/ai-teammates/control) for how approval works more broadly.

## Tips for Better Results [#tips-for-better-results]

| Tip                                             | Description                                                                                                                                   |
| ----------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
| Push back before sourcing                       | Vague JD terms like "senior" launder ambiguity into the search. Ask what they actually mean for this team before candidates get sourced.      |
| Search for passive candidates, not just inbound | A ranked pile of applicants isn't the same as finding people who fit the real bar but aren't applying.                                        |
| Personalize every outreach message              | Reference the one specific thing in a candidate's actual background that made them a match — not a mail-merge template.                       |
| Recalibrate when the bar turns out wrong        | If a hiring manager flags the bar as off, re-screen the current pipeline against the corrected bar instead of quietly living with a mismatch. |

## Common Questions [#common-questions]

<Accordions type="single">
  <Accordion title="Does this reject candidates on its own?">
    No. It screens and ranks, but doesn't reject anyone on your behalf, and outreach never sends without you seeing it first. Every proposed "no" should get a human glance before a candidate hears anything.
  </Accordion>

  <Accordion title="Can it message candidates on LinkedIn without me logging in?">
    Not fully. The native LinkedIn connector under Integrations only covers identity and, eventually, posting as you — it has no scope for search, browsing, or messaging. Candidate search and outreach run through a real cloud browser session, and when LinkedIn requires a two-factor code, you have to log in yourself in that shared session.
  </Accordion>

  <Accordion title="Does it treat inbound applicants differently from sourced candidates?">
    No. Inbound applicants get screened against the same bar as sourced candidates, not a looser standard just because they applied first.
  </Accordion>

  <Accordion title="What happens when the bar turns out to be wrong?">
    Tell the teammate directly what the hiring manager flagged. It re-screens the current pipeline against the corrected bar and reports who moves and who drops.
  </Accordion>

  <Accordion title="Where does the daily pipeline update post?">
    To `#hiring`, once the teammate has been added to that channel and the daily check-in automation is set up via Automations → Create via Chat.
  </Accordion>
</Accordions>

<Cards>
  <Card title="Industry & Specialized" href="/use-cases/industry-specialized" description="Back to the Industry & Specialized use case overview." />

  <Card title="Scan bestsellers for product gaps" href="/use-cases/industry-specialized/ecommerce-bestsellers" description="An e-commerce teammate that scans Amazon for what's trending you don't carry." />

  <Card title="Get a personal AI assistant" href="/use-cases/team-ops/personal-assistant" description="One teammate for whatever comes up." />
</Cards>
