Ir al contenido

Recruiting

Area: HR Workflow: workflows/hr/recruiting.json

End-to-end recruiting pipeline for clients who hire through Wulpers. The product is structured around six conceptual stages, of which two are implemented today (Onboarding + Consultant AI). The remaining four (LinkedIn sourcing, CV screening, calendar, human interview) live as roadmap stickies and are explicitly deferred.

The distinctive piece is Stage 2: Consultant AI — before sourcing humans, we run the brief through an LLM that flags responsibilities current AI tooling could cover. The requester gets a consultant note in their inbox and can revise the brief (e.g. replace a slot with an agent, split the role) before we hire.

Form Trigger: Receive Recruiting Brief
→ Code: Normalize Recruiting Brief
→ Google Sheets: Append Brief (recruiting_briefs tab, status: pending)
→ OpenAI: Suggest AI Replacements (gpt-4o-mini)
→ Code: Parse AI Suggestions (renders email HTML lists)
→ Google Sheets: Update Brief With AI Suggestions (match by brief_id, status: consulted)
→ Gmail: Send Consultant Report (HTML email to requester)
Stage Name Status Notes
1 Onboarding Implemented Form intake + persist brief.
2 Consultant AI Implemented LLM flags AI-replaceable tasks, emails report, updates row.
3 LinkedIn Recruiter Deferred Sourcing on LinkedIn requires Talent API partnership or ATS bridge.
4 CV Screening Deferred Gmail-triggered, parses PDFs, scores against the brief.
5 Pre-Interview Calendar Deferred Google Calendar invite for shortlisted candidates.
6 Client Interview Out of scope Human-led — lives outside n8n.
Field Type Required Notes
Requester Name text yes
Requester Email email yes
Company text yes
Role Title text yes E.g. “Senior Backend Engineer”.
Role Type dropdown yes Technical / Professional / Hybrid.
Seniority dropdown yes Junior / Mid / Senior / Lead / Manager.
Employment Type dropdown yes Full-time / Part-time / Contract / Freelance.
Location And Mode text yes E.g. “Remote”, “Hybrid Madrid”, “On-site NYC”.
Key Responsibilities textarea yes One per line.
Required Skills textarea yes Hard + soft, non-negotiable.
Nice-To-Have Skills textarea no
Budget Range text no E.g. “60k-80k USD/year”.
Start Date date no
Notes textarea no
{
"brief_id": "<ISO-8601 timestamp>",
"requester_name": "string",
"requester_email": "string",
"company": "string",
"role_title": "string",
"role_type": "Technical | Professional | Hybrid",
"seniority": "Junior | Mid | Senior | Lead | Manager",
"employment_type": "Full-time | Part-time | Contract | Freelance",
"location_mode": "string",
"responsibilities": "string",
"required_skills": "string",
"nice_to_have_skills": "string",
"budget_range": "string",
"start_date": "string",
"notes": "string",
"status": "pending",
"submitted_at": "<ISO-8601 timestamp>"
}

After the consultant pass, Code: Parse AI Suggestions enriches the item with:

{
"ai_replaceable_json": "<JSON string of [{task, agent_type, confidence, rationale}]>",
"human_only_json": "<JSON string of [string]>",
"ai_summary": "string",
"ai_replaceable_html": "<rendered <ul> for the email>",
"human_only_html": "<rendered <ul> for the email>",
"status": "consulted",
"last_updated_at": "<ISO-8601 timestamp>"
}

Lives in the existing workbook ($env.WORKBOOK_ID). One row per submitted brief; Stage 2 updates the same row keyed by brief_id.

Column Type Notes
brief_id string PK. ISO-8601 timestamp.
requester_name string
requester_email string
company string
role_title string
role_type enum Technical / Professional / Hybrid.
seniority enum Junior / Mid / Senior / Lead / Manager.
employment_type enum Full-time / Part-time / Contract / Freelance.
location_mode string
responsibilities string
required_skills string
nice_to_have_skills string
budget_range string
start_date string ISO-8601.
notes string
ai_replaceable json JSON array of { task, agent_type, confidence, rationale }. Filled by Stage 2.
human_only json JSON array of strings. Filled by Stage 2.
ai_summary string Consultant summary. Filled by Stage 2.
status enum pendingconsultedpublishingscreeninginterviewingclosed.
submitted_at string ISO-8601.
last_updated_at string ISO-8601. Refreshed by Stage 2 and every subsequent stage.

Sent via Gmail to requester_email with subject Consultant note on <role_title> at <company>. HTML body includes:

  • A list of AI-replaceable tasks with proposed agent type + confidence + rationale.
  • A list of human-only tasks.
  • A short summary.
  • An invitation to revise the brief before sourcing.
Credential type Used by
googleSheetsOAuth2Api Google Sheets: Append Brief, Google Sheets: Update Brief With AI Suggestions.
openAiApi OpenAI: Suggest AI Replacements — bind in n8n on import.
gmailOAuth2 Gmail: Send Consultant Report — bind in n8n on import.

See credentials/README.md.

commercial.

  • active: false.
  • Stages 1 + 2 are the only implemented stages.

Goal: publish the job and source candidates on LinkedIn.

Why deferred: n8n’s built-in linkedIn node only posts to a personal feed, which is not a job posting. Real sourcing on LinkedIn Recruiter / Talent Solutions requires either:

  • Official LinkedIn Talent API — requires partnership and case-by-case approval.
  • An ATS that bridges to LinkedIn (Workable, Greenhouse, JobAdder, Lever) — paid SaaS.
  • A scraping service such as Phantom Buster or Apify — recurring cost and against LinkedIn ToS.

Trigger when built: status transition consulted → publishing on the brief row, either by a manual edit or a follow-up confirmation flow after the consultant note.

Goal: filter inbound CVs against the brief and surface the strongest matches.

Trigger when built: Gmail Trigger on a dedicated alias (e.g. jobs@<company> — exact alias to be decided per client).

Pipeline (planned):

  1. Pull PDF / DOCX attachments from incoming emails matching the alias.
  2. Extract text (PDF text layer first; OCR fallback for image-PDFs via OpenAI Vision or Tesseract).
  3. Score each candidate against required_skills + nice_to_have_skills with OpenAI; output { candidate_name, candidate_email, fit_score, strengths, gaps }.
  4. Append candidates above a threshold to a candidates tab keyed by brief_id + candidate email; deduplicate.

Stage 5 — Pre-Interview Calendar (deferred)

Sección titulada «Stage 5 — Pre-Interview Calendar (deferred)»

Goal: book pre-interview slots between the requester and shortlisted candidates.

Trigger when built: candidate row marked shortlisted in the candidates tab (manual or auto when fit_score ≥ threshold).

Plan:

  • Create a Google Calendar event with the candidate + requester as attendees.
  • Attach a Meet link.
  • Send the invite via Gmail (or rely on Calendar’s native invitation email).
  • If the candidate declines, log status declined and notify the requester.

Goal: human-led interview. Lives outside n8n.

Loop back: after the meeting the requester updates the candidate row (hired / rejected / next_round). That status change can later trigger contract drafting (e.g. via DocuSign) or a polite rejection email.

  • Status state machine. Confirm the brief status enum (pendingconsultedpublishingscreeninginterviewingclosed) once Stage 3 is built. The dropped terminal status may be needed too.
  • Stage 2 idempotency. Re-running the consultant pass on an already-consulted brief currently overwrites the previous AI columns silently. Decide if we want to version them (ai_replaceable_v1, ai_replaceable_v2) or always overwrite.
  • Multilingual. The consultant prompt is instructed to “respond in the same language as the brief.” Confirm with a non-English test (e.g. Spanish brief → Spanish email).
  • PII. The brief stores requester email but no candidate PII yet. Stage 4 introduces candidate PII — decide retention policy before that stage ships.