Daily stalled-candidate nudge from Ashby to recruiters in Slack

Every weekday at 8am, DM each recruiter a prioritized list of their candidates that have been sitting too long in their current Ashby stage.

Agentic Task
AshbySlack BotHR & PeopleOperationsDaily DigestsNotifications & Alerts

Build me an agent workflow that runs every weekday at 8am in my local time zone and nudges each recruiter in Slack about the candidates of theirs that have stalled in our Ashby pipeline.

Trigger: cron, weekdays at 8am.

Step 1. Pull active candidates from Ashby. Use Ashby's List Applications operation, paginated through all results, filtered to active applications only (no archived, hired, or rejected). For each application, capture its id, current interview stage name, the assigned recruiter (the Ashby userId on the application), the candidate id, and the job id.

Step 2. Compute stage dwell time. For each active application, call Ashby's List Application History to retrieve the timeline of stage changes. Find the most recent stage-change event whose target stage matches the application's current stage, and use that timestamp as the stage entry time. Compute days_in_stage = now minus stage_entry_time. If there is no stage-change event (the candidate has been in their original stage since application created), fall back to the application's createdAt.

Step 3. Decide if it counts as stalled. Use a configurable default threshold of 7 days. Use a stricter threshold of 3 days for late-stage rounds. Late-stage means the current stage name contains any of: Onsite, Final, Offer, Reference. Treat both threshold numbers and the late-stage keyword list as easily editable constants at the top of the workflow. Skip applications under their threshold.

Step 4. Enrich each stalled application. Call Ashby's Get Candidate Info for the candidate name and primary email. Call Ashby's Get Job Info for the job title and department. Call Ashby's Get User Info on the assigned recruiter to get the recruiter's name and email. If the application has no assigned recruiter, skip it (or, optionally, collect those into a fallback list).

Step 5. For each stalled application, generate a one-line suggested next action based on the current stage and how long it has been sitting. Examples: for an old Application Review row, suggest "review and advance or reject." For an old phone screen, suggest "chase the screener for feedback." For an old Onsite, suggest "ping the hiring manager for debrief." For an old Offer, suggest "check in with the candidate." For anything sitting more than 14 days, suggest "send rejection if no path forward." Keep these one short sentence each.

Step 6. Group stalled records by assigned recruiter. For each recruiter that has at least one stalled candidate:

a. Sort their list by days_in_stage descending so the most stuck candidates show up first.

b. Use Slack Bot's Look Up User by Email with the recruiter's Ashby email to resolve their Slack user id. If lookup fails, log it and continue.

c. Use Slack Bot's Open a Conversation with that user id to get a DM channel id.

d. Use Slack Bot's Send a Message to post one DM with a short header ("Good morning, here are 5 candidates that have been sitting too long") followed by a bulleted list. Each bullet should include candidate name, job title, current stage, days in stage, and the one-line suggested next action. Keep it scannable. Use Slack mrkdwn formatting and bold the candidate name.

Step 7. If a recruiter has zero stalled candidates, do not message them. Quiet mornings should produce no Slack noise.

Constraints and behavior:

One DM per recruiter per run, never one message per candidate. Be polite about Ashby and Slack rate limits. Skip and log any recruiter whose Slack lookup by email fails rather than failing the whole run. Never modify anything in Ashby; this workflow is read-only on the Ashby side and write-only-to-DMs on the Slack side.

Integrations to use: Ashby (List Applications, List Application History, Get Candidate Info, Get Job Info, Get User Info) and Slack Bot (Look Up User by Email, Open a Conversation, Send a Message).

Additional information

What does this prompt do?
  • Scans your active Ashby pipeline every weekday morning and finds candidates who have been parked in the same stage too long.
  • Uses a stricter limit for late-stage rounds like Onsite and Offer so finalists never quietly age out.
  • Groups stalled candidates by the assigned recruiter and sends each person a single Slack DM with their list.
  • Adds a one-line suggested next action per candidate, like ping the hiring manager or send a rejection.
  • Stays quiet for any recruiter who has nothing stalled, so the Slack message only shows up when there is work to do.
What do I need to use this?
  • An Ashby account with admin access so you can create an API key for the integration.
  • A Slack workspace where the General Input bot can be installed and send direct messages.
  • Recruiter assignments filled in on your Ashby applications so we know who to nudge.
  • Recruiter email addresses in Ashby that match their Slack login email.
How can I customize it?
  • Change the schedule. Default is 8am on weekdays, but you can switch to daily, three times a week, or a different time zone.
  • Tune the day thresholds. Default is 7 days for normal stages and 3 days for late-stage rounds like Onsite and Offer. Both numbers are easy to adjust.
  • Decide which stages count as late-stage. Add or remove stage names like Final Round, Reference Check, or Offer.
  • Tweak the suggested next actions, or have the message include extra context like the job title, source, or days since application created.
  • Cap the number of candidates listed per recruiter, or add a fallback channel for candidates with no recruiter assigned.

Frequently asked questions

What counts as a stalled candidate?
Anyone whose current Ashby application stage has not changed in more than your threshold number of days. The default is 7 days for most stages and 3 days for late-stage rounds like Onsite and Offer, and both are configurable.
Will recruiters get a DM every morning even when nothing is stalled?
No. The agent only sends a Slack message to a recruiter who actually has stalled candidates that day. Quiet days produce no notifications.
What if a candidate has no recruiter assigned in Ashby?
By default those candidates are skipped. You can extend the prompt to also send a summary of unassigned stalled candidates to a fallback Slack channel or to a hiring lead.
Does this move candidates or change anything in Ashby?
No. The agent only reads from Ashby and sends messages in Slack. It never changes a stage, archives a candidate, or edits any Ashby record.
How does it figure out which Slack user to message?
It looks up each recruiter in Slack by the email address on their Ashby user account. As long as those emails match, the DM lands with the right person.
Can I change the suggested next action per candidate?
Yes. The agent generates short prompts like send rejection or ping hiring manager based on stage and dwell time. You can edit the rules, add your own phrasing, or have it pull context from candidate notes.

Stop letting candidates quietly age out of your pipeline.

Connect Ashby and Slack once, and Geni nudges each recruiter every weekday morning with the candidates that have been sitting too long.