If you searched for “OpenClaw HR and recruiting automation screening and scheduling”, you are probably fighting the same battle I was a month ago: too many applicants, not enough hours. Below is the exact playbook I used to wire OpenClaw 0.42.1 into our existing HR stack (Greenhouse, Calendly, Gmail, Slack) and save about 8-10 recruiter hours per role. I’ll walk through resume screening, interview scheduling, ongoing candidate communication, feedback collection, and finally offer letter generation. I also cover the legal landmines—GDPR, EEOC, bias audits—because ignoring them will bite you later.

Why use OpenClaw for HR and recruiting automation?

I tried the built-in automation features in Greenhouse and Lever. They’re fine for drip emails, but anything more complex—like scraping GitHub activity or aligning interviewer calendars across departments—breaks down fast. OpenClaw’s agent model lets me:

  • Call 800+ SaaS APIs (via Composio) from one Node.js process.
  • Keep persistent memory of each candidate across channels.
  • Trigger browser automation for sites that lack APIs (looking at you, Workday).
  • Run cron-like scheduled tasks for follow-ups.
  • Expose a simple Slack or WhatsApp interface so recruiters can nudge the agent in plain English.

The trade-off: you now own the glue code and have to maintain it. If you’re allergic to JavaScript or don’t have basic DevOps chops, stop here and pay for a turnkey vendor. Otherwise, keep reading.

Setting up the agent: screening and scheduling scaffold

Assumptions:

  • Node 22.3+ installed locally or on a CI box.
  • Greenhouse API key (or Lever—swap endpoints below).
  • Calendly OAuth app created (the free tier is enough).
  • Slack bot token with chat:write and commands scopes.

Install OpenClaw globally or add it to your repo:

npm install -g openclaw@0.42.1 # or yarn dlx openclaw init hr-agent

The wizard creates two processes:

  • gateway – the React/Next.js UI. I turn this off on the server and only run it locally.
  • daemon – the long-running agent. This is what we’ll deploy.

Now edit ~/openclaw/agents/hr-agent/index.ts (I’ll TypeScript throughout; strip types if you prefer JS):

import { Agent, ToolKit } from 'openclaw'; import { Greenhouse, Gmail, Slack, Calendly } from '@composio/sdk'; const gh = new Greenhouse({ apiKey: process.env.GREENHOUSE_KEY }); const mail = new Gmail({ token: process.env.GMAIL_TOKEN }); const slack = new Slack({ token: process.env.SLACK_BOT }); const cal = new Calendly({ token: process.env.CALENDLY_TOKEN }); export const hrAgent: Agent = new Agent({ name: 'RecruiterClaw', memory: 'kv', // Redis by default tools: ToolKit.compose(gh, mail, slack, cal), prompt: `You are an ATS copilot. Keep responses short, neutral and ADA compliant.` });

Boot it:

openclaw start hr-agent

Automated resume screening workflow

Classic flow: candidate applies in Greenhouse ➜ we fetch the resume ➜ pass it through an LLM rubric ➜ update the application stage or leave a rejection note.

Webhook handler

Create a Greenhouse “Candidate has submitted application” webhook pointed at https://your-server.com/hooks/greenhouse.

// hooks/greenhouse.ts import { hrAgent } from '../agents/hr-agent'; import { parseResume } from './lib/parse'; export async function POST(req: Request) { const payload = await req.json(); const { application_id } = payload; const resumeUrl = payload.resume_url; // 1. Parse PDF using AWS Textract or Affinda const resume = await parseResume(resumeUrl); // 2. Ask OpenAI or local Llama for a score const { score, notes } = await hrAgent.chat( `Score this resume for Senior Backend Engineer out of 10 and justify in 3 bullets:\n${resume}` ); // 3. Update Greenhouse if (score > 7) { await gh.moveToStage({ application_id, stage: 'Phone Screen' }); } else { await gh.reject({ application_id, note: `Auto-reject: ${notes}` }); } return new Response('ok'); }

Heavy lifting sits in parseResume; pick any parsing service. The OpenClaw agent is just the orchestrator.

Things that bit me:

  • Greenhouse rate limits at 500 requests/5 min. Batch updates if you have high volume.
  • LLM hallucinations. I store the raw score and the agent’s tokens in Postgres for audit.
  • GDPR: we auto-delete resumes after 180 days via a nightly cron.

Self-serve interview scheduling with Calendly and Slack

Once a candidate reaches “Phone Screen”, we fire an email with a Calendly link and track no-shows automatically. OpenClaw’s scheduler API replaced a patchwork of zaps and Google App Scripts.

Trigger email + DM

hrAgent.on('stageChanged', async ({ application, newStage }) => { if (newStage !== 'Phone Screen') return; const { candidate } = application; const slotUrl = await cal.createInviteeLink({ user: 'me@company.com', duration: 30, buffer: 15 }); await mail.send({ to: candidate.email, subject: 'Your phone screen – pick a time', html: `Hi ${candidate.first_name},
Pick any slot here: ${slotUrl}` }); // Notify recruiter in Slack await slack.postMessage({ channel: '#hiring-backend', text: `Sent phone screen invite to ${candidate.first_name} ${candidate.last_name}` }); });

If the candidate books, Calendly pings our /hooks/calendly endpoint; we update Greenhouse and slide the candidate to “Scheduled”. We also write a nightly job that marks no-shows and sends a reschedule email.

Watcher code:

// cron/no-show.ts import { subMinutes, isAfter } from 'date-fns'; hrAgent.schedule('0 * * * *', async () => { // every hour const meetings = await cal.listEvents({ status: 'scheduled' }); for (const m of meetings) { const started = isAfter(new Date(), new Date(m.start_time)); const late = isAfter(new Date(), subMinutes(new Date(), -10)); if (started && late && !m.joined) { await gh.addNote({ application_id: m.metadata.applicationId, note: 'Auto-flag: candidate no-show' }); } } });

Candidate communication and status updates

Recruiters hate opening the ATS just to see “is background check done?”. I wired Slack slash commands so they can query the agent in plain English.

Slack command example

// slack/commands/status.ts slack.on('/candidate', async ({ text, user_id, respond }) => { const [email] = text.split(' '); const cand = await gh.lookupCandidate({ email }); if (!cand) return respond(`No candidate with email ${email}`); const stage = cand.current_stage; const links = cand.application_ids.map(id => `https://greenhouse.io/applications/${id}`); respond(`${cand.first_name} is in stage *${stage}*\n${links.join('\n')}`); });

We also let candidates ping the agent over WhatsApp (using the Twilio connector) for quick Q&A—salary range, location policy, etc. All messages get logged back to the Greenhouse activity feed for compliance.

Collecting structured feedback after interviews

Interviewers forget to submit scorecards. The agent now DMs them right after the Calendly event ends, parses the free-text answers, and fills the ATS form.

// events/calendly.completed.ts cal.on('event_completed', async ({ event }) => { const { interviewerSlackId, applicationId } = event.metadata; await slack.postMessage({ channel: interviewerSlackId, text: 'Interview done – paste your notes here. Use headings: Pros, Cons, Hire/No Hire.' }); const reply = await slack.waitForReply(interviewerSlackId, { timeout: '2h' }); const { structured } = await hrAgent.chat( `Convert to JSON with keys pros, cons, decision:\n${reply.text}` ); await gh.submitScorecard({ application_id: applicationId, pros: structured.pros.join('\n'), cons: structured.cons.join('\n'), decision: structured.decision }); });

Completion rate went from 72% ➜ 97% in two weeks. The 3% are people on flights; fine.

Generating and sending offer letters securely

I briefly considered DocuSign’s API directly but the nightmare of template IDs pushed me to PandaDoc. The agent populates the template, emails the PDF, and tracks signature status.

import { PandaDoc } from '@composio/sdk'; const pd = new PandaDoc({ token: process.env.PANDADOC }); async function sendOffer(applicationId: string) { const app = await gh.getApplication({ application_id: applicationId }); const cand = app.candidate; const comp = await compTool.getCompRecommendation(app.role, app.level); const docId = await pd.createDocument({ template_id: 'tmpl_8f2be58d1', name: `Offer – ${cand.first_name} ${cand.last_name}`, recipients: [{ email: cand.email, role: 'candidate' }], tokens: { CAND_NAME: `${cand.first_name} ${cand.last_name}`, BASE_SALARY: comp.base.toLocaleString('en-US', { style: 'currency', currency: 'USD' }), START_DATE: comp.startDate.toISOString().split('T')[0] } }); await pd.sendDocument({ document_id: docId }); await gh.moveToStage({ application_id: applicationId, stage: 'Offer Sent' }); }

The agent polls PandaDoc every 10 minutes for document_completed. On signature, it upgrades Greenhouse to “Hired” and triggers IT onboarding tickets via Jira’s REST API.

Legal and ethical considerations: bias, transparency, GDPR/EEOC

Throwing an LLM at resumes is easy; passing a compliance audit is not. Here’s what kept our legal team calm:

  • Bias testing: Every month we rerun 500 anonymized resumes (names stripped) through the screening prompt, plot scores by genderized first name (Genderize.io) and ethnicity proxy (NamePrism). A threshold of ±1 σ triggers a prompt review.
  • Prompt transparency: We treat prompt templates as “selection procedures” under the Uniform Guidelines. Recruiters can see and diff them in a GitHub repo.
  • GDPR data subject rights: Candidates can text “/export” to the WhatsApp bot. The agent bundles all stored data (Redis memory, Greenhouse notes, Slack logs) into a ZIP and emails it. Deletion works the same.
  • EEOC: We log every automated decision with rationale and persist to Postgres for 4 years, as required for companies >100 employees.
  • Security: Secrets live in AWS Secrets Manager; the daemon runs on Fargate with IAM roles per tool. No hard-coded tokens in code.

Some jurisdictions (NYC Local Law 144) now require yearly bias audits of “automated employment decision tools”. Our stored logs and monthly bias charts feed directly into the audit report—no extra work.

What we still can't automate (yet) and next steps

Humans still do final culture interviews. I haven’t found a good way to quantify “would you enjoy a coffee with this person” without turning into Black Mirror. Also, salary negotiation messages are drafted by the agent but manually reviewed—one bad decimal place could cost thousands.

Next on my list:

  • Voice screening over Twilio with real-time transcription to cut recruiter phone time.
  • Using OpenClaw’s browser tool to pull GitHub PR velocity as an objective metric.
  • Connecting to SAP SuccessFactors for automatic provisioning after hire.

If you want to replicate or improve this setup, the repo is public at github.com/myorg/openclaw-hr-playbook. PRs welcome—especially around bias metrics. Happy automating.