# Recruit Workflow

> Execute the full recruitment automation pipeline - load candidate CSVs from MinIO, evaluate candidates against job descriptions, enrich contacts via Clay, draft personalized outreach emails, and send via Mailgun. Use when processing recruitment leads, evaluating candidate fit, or sending outreach campaigns.

- Skill: `shakudo-io/recruit-workflow` (Agent Skill, multi-file: 7 files)
- Install (CLI): `npx skillmds@latest add shakudo-io/recruit-workflow`
- Raw SKILL.md: https://api.skillmd.com/api/skills/shakudo-io/recruit-workflow/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: DevOps & Infra
- License: MIT
- Author: Shakudo-io (https://skillmd.com/u/shakudo-io)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/shakudo-io/recruit-workflow

---


# Recruitment Workflow Automation

Execute the end-to-end recruitment pipeline without a TUI. You (the AI agent) perform candidate evaluation and email drafting directly - no external LLM calls needed.

## When to Use This Skill

- Processing candidate lists from LinkedIn/Evaboot exports
- Evaluating candidates against job descriptions
- Enriching contacts to find email addresses
- Drafting and sending personalized outreach emails
- Managing recruitment campaigns stored in MinIO

## Prerequisites

### Environment Variables Required

```bash
# MinIO Configuration
MINIO_ENDPOINT=minio.hyperplane-minio.svc.cluster.local:9000
MINIO_ACCESS_KEY=<access_key>
MINIO_SECRET_KEY=<secret_key>
MINIO_BUCKET=candidates
MINIO_SECURE=false

# Mailgun Configuration
MAILGUN_API_KEY=<api_key>
MAILGUN_DOMAIN=<domain>
MAILGUN_FROM_EMAIL=recruiting@company.com
MAILGUN_FROM_NAME=Company Recruiting

# Clay Configuration (for contact enrichment)
CLAY_ENDPOINT=<clay_webhook_url>

# Lever Configuration (for job descriptions)
LEVER_API_KEY=<api_key>
```

### Python Dependencies

The helper scripts use inline dependencies (PEP 723). Run with `uv run`:
```bash
uv run scripts/minio_client.py --help
```

## Complete Workflow

### Phase 1: Setup & Data Loading

#### Step 1.1: List Available Candidate CSVs

```bash
uv run scripts/minio_client.py list-csvs
```

Returns all CSV files in the `candidates` bucket under `raw_data/` prefix.

#### Step 1.2: Download and Parse Candidate List

```bash
uv run scripts/minio_client.py download-csv "raw_data/your-list/candidates.csv"
```

Returns JSON array of candidate records. Each candidate has:
- `name`, `email` (may be empty), `linkedin_url`
- `current_company`, `current_title`
- Raw CSV data preserved

#### Step 1.3: Fetch Job Description from Lever

```bash
uv run scripts/lever_client.py list-postings
uv run scripts/lever_client.py get-posting <posting_id>
```

Or create a custom JD inline for evaluation.

### Phase 2: Candidate Evaluation

**YOU (the AI agent) perform this step directly.** No LLM API calls needed.

For each candidate, evaluate against the job description:

1. **Read the candidate profile**:
   - Name, current title, current company
   - Years of experience (if available)
   - LinkedIn URL for additional context

2. **Compare against JD requirements**:
   - Technical skills match
   - Experience level appropriate
   - Industry/domain relevance

3. **Assign fit score**:
   - `1` = Qualified (proceed to outreach)
   - `0` = Not qualified (skip or review later)

4. **Write brief reasoning** (2-3 sentences):
   - Why they fit or don't fit
   - Key strengths or gaps

Example evaluation output:
```json
{
  "email": "john@example.com",
  "fit_score": 1,
  "reasoning": "Strong backend experience at Series B startup. 5 years Python/Go matches our stack. Previous ML platform work aligns with role."
}
```

### Phase 3: Contact Enrichment (If Needed)

For candidates without email addresses:

```bash
uv run scripts/clay_client.py enrich "<linkedin_url>"
```

Returns enriched email if found. Save enrichment results:
```bash
uv run scripts/minio_client.py save-enrichment "raw_data/your-list/candidates.csv" "<linkedin_url>" "<email>"
```

### Phase 4: Email Drafting

**YOU (the AI agent) draft emails directly.** 

For each qualified candidate, create a personalized outreach email:

#### Guidelines:
- **Subject**: Specific, mentions their background (not generic "Opportunity")
- **Opening**: Reference something specific about them (company, role, project)
- **Value prop**: Why this role/company is relevant to THEM
- **Call to action**: Clear next step (call, reply, calendar link)
- **Length**: Under 150 words - busy people skim

#### Email Template Structure:
```
Subject: [Specific hook related to their background]

Hi [First Name],

[1 sentence showing you know their background - current role, company, or achievement]

[2-3 sentences on the opportunity and why it's relevant to them specifically]

[Clear call to action - what do you want them to do?]

Best,
[Sender Name]
```

#### Save Draft to MinIO:
```bash
uv run scripts/minio_client.py save-draft \
  --job-id "<job_id>" \
  --candidate-email "<email>" \
  --subject "<subject>" \
  --body "<body>"
```

### Phase 5: Email Sending

#### Step 5.1: Send Individual Email

```bash
uv run scripts/mailgun_client.py send \
  --to "<recipient_email>" \
  --subject "<subject>" \
  --body "<body>"
```

#### Step 5.2: Send Follow-up (Threading)

```bash
uv run scripts/mailgun_client.py send-followup \
  --to "<recipient_email>" \
  --subject "Re: <original_subject>" \
  --body "<followup_body>" \
  --in-reply-to "<original_message_id>"
```

#### Step 5.3: Record Sent Email

```bash
uv run scripts/minio_client.py record-sent \
  --campaign "<campaign_folder>" \
  --candidate-email "<candidate_email>" \
  --recipient-email "<recipient_email>" \
  --subject "<subject>" \
  --message-id "<message_id>"
```

### Phase 6: Results & Reporting

#### Save Evaluation Results

```bash
uv run scripts/minio_client.py upload-results \
  --source-path "raw_data/your-list/candidates.csv" \
  --results '<json_array_of_results>'
```

Creates `raw_data/your-list/candidates_results.csv` with evaluation data.

#### Check Campaign Status

```bash
uv run scripts/minio_client.py get-sent-emails "<campaign_folder>"
```

## Workflow Checklist

- [ ] Verify environment variables are set
- [ ] List and select candidate CSV from MinIO
- [ ] Download candidate data
- [ ] Get or create job description
- [ ] Evaluate each candidate (YOU do this directly)
- [ ] Enrich contacts missing emails (via Clay)
- [ ] Draft personalized emails (YOU do this directly)
- [ ] Send emails via Mailgun
- [ ] Record sent emails and save results to MinIO

## Error Handling

### Common Issues

| Error | Cause | Solution |
|-------|-------|----------|
| MinIO connection failed | Wrong endpoint or credentials | Check MINIO_* env vars |
| CSV encoding error | Non-UTF8 file | Script auto-detects encoding |
| Clay timeout | Enrichment taking too long | Retry or skip candidate |
| Mailgun 401 | Invalid API key | Verify MAILGUN_API_KEY |

### Retry Logic

All scripts include exponential backoff. If a transient error occurs, wait and retry:
```bash
# Scripts automatically retry 3 times with backoff
uv run scripts/minio_client.py download-csv "path/to/file.csv"
```

## File Reference

- `scripts/minio_client.py` - MinIO operations (list, download, upload, drafts)
- `scripts/mailgun_client.py` - Email sending with threading support
- `scripts/clay_client.py` - Contact enrichment via Clay webhook
- `scripts/lever_client.py` - Fetch job descriptions from Lever API
- `references/workflow-stages.md` - Detailed stage documentation
- `references/email-templates.md` - Email drafting best practices

## Example Session

```
User: Process the ex-founders candidate list for the SDE role

Agent activates recruit-workflow skill:
1. Lists CSVs, finds "raw_data/ex-founders-sf/candidates.csv"
2. Downloads 47 candidates
3. Fetches SDE job posting from Lever
4. Evaluates each candidate:
   - 12 qualified (fit_score=1)
   - 35 not qualified (fit_score=0)
5. Enriches 8 candidates missing emails via Clay
6. Drafts 12 personalized emails
7. Sends via Mailgun (or saves as drafts for review)
8. Uploads results CSV to MinIO
```

