Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 21 additions & 13 deletions claw4hr-passive-talent-intelligence/.env.example
Original file line number Diff line number Diff line change
@@ -1,14 +1,22 @@
# HrFlow.ai (get from hackathon organizers)
# HrFlow.ai
HRFLOW_API_KEY=ask_...
HRFLOW_API_EMAIL=your-email@example.com
HRFLOW_SOURCE_KEY=your-source-key-here
HRFLOW_BOARD_KEY=your-board-key-here
HRFLOW_ALGORITHM_KEY=your-algorithm-key-here

# Sourcing passif (optional)
PROXYCURL_API_KEY=your-proxycurl-key-here
GITHUB_TOKEN=ghp_your-github-token-here

# Ollama LLM (optional — Mac Mini via Tailscale)
OLLAMA_BASE_URL=http://localhost:11434
OLLAMA_MODEL=qwen3:14b
HRFLOW_API_EMAIL=
HRFLOW_BOARD_KEY=
HRFLOW_SOURCE_KEY=
HRFLOW_LIVE_SOURCE_KEY=
HRFLOW_ALGORITHM_KEY=
NEXT_PUBLIC_HRFLOW_DEFAULT_JOB_KEY=

# Supabase (auth + persistence)
NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_ANON_KEY=

# Mistral (LLM for chat / SWOT)
MISTRAL_API_KEY=

# Trigger.dev (sourcing pipeline)
TRIGGER_SECRET_KEY=
TRIGGER_WEBHOOK_SECRET=

# App
NEXT_PUBLIC_APP_URL=http://localhost:3000
60 changes: 60 additions & 0 deletions claw4hr-passive-talent-intelligence/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.*
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/versions

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
*.pem

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
.pnpm-debug.log*

# env files
.env
.env.local
.env*.local
!.env.example

# vercel
.vercel

# typescript
*.tsbuildinfo
next-env.d.ts

# AI assistant tooling (not source code)
.claude/
.agents/
skills-lock.json
.mcp.json
CLAUDE.md
AGENTS.md

# Internal docs
CONTEXT.md
DEMO_SCRIPT.md
PITCH_DECK.md
OPENCLAW_PROMPT.md
CLAW4HR_VISION.md
.superpowers/
198 changes: 118 additions & 80 deletions claw4hr-passive-talent-intelligence/README.md
Original file line number Diff line number Diff line change
@@ -1,109 +1,147 @@
# Claw4HR — Passive Talent Intelligence
# Claw4HR — AI Talent Sourcing Platform

> AI recruiter agent: describe a role, get scored candidates instantly.
Passive talent sourcing agent. Built for the HrFlow GenAI & RH Hackathon 2026.

## What it does
A recruiter describes a role in natural language → multi-source agents discover matching profiles on GitHub, LinkedIn, Reddit, and the web → HrFlow scores each candidate → the recruiter interacts with profiles via Q&A and manages a pipeline.

A recruiter describes a position via chat (text or Telegram voice message). The agent:
1. Extracts criteria (skills, location, seniority) via NLP
2. Finds the most relevant job in the HrFlow board
3. Scores indexed profiles (10k+) using HrFlow AI Scoring
4. Displays top candidates with animated matching scores, clickable skills, and detailed profiles
5. Provides SWOT analysis (strengths/gaps) and Q&A per candidate
**Deploy:** https://hrflowhackathon2026.vercel.app

The real-time pipeline feed traces every step of the process.
---

**Live demo:** https://hrflowhackathon2026.vercel.app
## Setup

## HrFlow.ai APIs used
```bash
npm install
cp .env.example .env.local # fill in your keys
npm run dev # http://localhost:3000
```

- `GET /v1/profiles/searching` — List indexed profiles
- `GET /v1/profiles/scoring` — AI scoring of profiles against a job
- `GET /v1/profile/asking` — Q&A on a specific profile
- `GET /v1/profile/upskilling` — SWOT analysis (strengths + gaps)
- `POST /v1/profile/parsing` — Upload and parse a CV
- `GET /v1/jobs/searching` — List jobs from a board
## Environment variables

## How to run
| Variable | Description |
|---|---|
| `HRFLOW_API_KEY` | HrFlow API key (`ask_...`) |
| `HRFLOW_API_EMAIL` | HrFlow account email |
| `HRFLOW_SOURCE_KEY` | HrFlow profile source key |
| `HRFLOW_BOARD_KEY` | HrFlow job board key |
| `TRIGGER_SECRET_KEY` | trigger.dev secret key (sourcing pipeline) |
| `TRIGGER_PROJECT_ID` | trigger.dev project ID |
| `TRIGGER_WEBHOOK_SECRET` | Shared secret for webhook auth (optional) |
| `NEXT_PUBLIC_APP_URL` | App URL used to build the webhook callback |

### Prerequisites
---

- Node.js 20+
- npm
## Architecture

### Setup
### User flow

```bash
cd claw4hr-passive-talent-intelligence
```
SearchView → LoadingView → ResultsView → ProfileDetailView
```

# Install dependencies
npm install
1. **SearchView** — natural language search bar
2. **LoadingView** — animated agents (GitHub / LinkedIn / Reddit / Web) with live terminal feed
3. **ResultsView** — scored candidate grid with filters and analytics
4. **ProfileDetailView** — full profile + HrFlow Q&A + SWOT analysis

# Copy environment variables
cp .env.example .env
# Then fill in your actual API keys in .env
### Data flow

# Start the app (dev mode)
npm run dev
# App runs at http://localhost:3000
```
Recruiter types a query
POST /api/trigger/run → triggers sourcing-task on trigger.dev
sourcing-task runs externally → POSTs profiles + agent events to webhook
POST /api/trigger/webhook → pushes to in-memory event store
GET /api/trigger/stream (SSE) → dashboard updates in real time
```

### Environment variables

| Variable | Required | Description |
|----------|----------|-------------|
| `HRFLOW_API_KEY` | Yes | HrFlow.ai API key (prefix `ask_`) |
| `HRFLOW_API_EMAIL` | Yes | HrFlow.ai account email |
| `HRFLOW_SOURCE_KEY` | Yes | HrFlow.ai source containing profiles |
| `HRFLOW_BOARD_KEY` | Yes | HrFlow.ai board containing jobs |
| `HRFLOW_ALGORITHM_KEY` | Yes | HrFlow.ai AI scoring algorithm key |
| `PROXYCURL_API_KEY` | No | LinkedIn enrichment (Proxycurl) |
| `GITHUB_TOKEN` | No | GitHub passive sourcing |
| `OLLAMA_BASE_URL` | No | Ollama LLM endpoint |
| `OLLAMA_MODEL` | No | Ollama model (default: qwen3:14b) |

## Architecture
### File structure

```
app/
page.tsx Dashboard 3-column layout
layout.tsx Layout with Geist font
globals.css Dark "mission control" theme + animations
components/
TopBar.tsx Status bar (OpenClaw, Indeed, HrFlow connections)
Dashboard.tsx Main orchestrator (state, fetch, layout)
WhatsAppPanel.tsx Recruiter chat (left panel)
CandidatePanel.tsx Candidate cards with scoring (center)
AgentFeed.tsx Real-time agent pipeline feed (right)
Dashboard.tsx Orchestrator (state, SSE, handlers)
SearchView.tsx Search bar
LoadingView.tsx Animated agents + live terminal
ResultsView.tsx Profile grid + live agent strip
CandidateCard.tsx Candidate card (score, skills, sources)
ProfileDetailView.tsx Full profile + Q&A
PixelAgent.tsx Pixel art sprites per source
ScoreRing.tsx Animated score ring
lib/
hrflow.ts Centralized HrFlow client
types.ts TypeScript types
api/hrflow/
parse/route.ts POST — Upload & parse CV
score/route.ts GET — Score profiles vs job
ask/route.ts GET — Q&A on a profile
upskill/route.ts GET — SWOT analysis profile vs job
profiles/route.ts GET — List indexed profiles
jobs/route.ts GET — List board jobs
api/openclaw/
webhook/route.ts POST — Receive OpenClaw events
events/route.ts GET — Dashboard polling (cursor-based)
types.ts TypeScript types (SourcedProfile, FeedLog, ...)
hrflow.ts HrFlow API client
eventStore.ts In-memory pub/sub (webhook → SSE stream)
api/
trigger/
run/route.ts POST — start a sourcing run via trigger.dev
webhook/route.ts POST — receive profiles + events from the task
stream/route.ts GET — SSE stream to dashboard
events/route.ts GET — cursor-based polling alternative
hrflow/
parse/route.ts POST — parse a resume
score/route.ts GET — score profiles against a job
ask/route.ts GET — Q&A on a profile
upskill/route.ts GET — SWOT strengths/gaps analysis
profiles/route.ts GET — list profiles
jobs/route.ts GET — list jobs
account/
searches/route.ts Search history (Supabase)
shortlist/route.ts Shortlisted candidates (Supabase)
outreach/route.ts Outreach messages (Supabase)
demo/
ask/route.ts Q&A fallback (Mistral)
swot/route.ts SWOT fallback (Mistral)
outreach/
generate/route.ts Outreach message generation (Mistral)
trigger/
sourcing-task.ts trigger.dev task — multi-source candidate discovery
```

## Screenshots
---

![Preview](./assets/preview.png)
## Connecting the sourcing pipeline

## Stack
The sourcing task (`trigger/sourcing-task.ts`) is a trigger.dev v3 task. Once configured, it receives a query and webhook URL, runs the multi-source sourcing logic, and POSTs each discovered profile back to the dashboard.

- **Frontend**: Next.js 16, React 19, Tailwind CSS v4
- **Backend**: Next.js API Routes
- **AI/HR**: HrFlow.ai (parsing, scoring, asking, AI algorithm)
- **Orchestrator**: OpenClaw
- **LLM**: Ollama + Qwen3 14B
- **Chat**: Telegram (via OpenClaw)
### Sending profiles to the dashboard

## Team
```bash
curl -X POST https://your-app.vercel.app/api/trigger/webhook \
-H "Content-Type: application/json" \
-H "x-trigger-secret: YOUR_WEBHOOK_SECRET" \
-d '{
"channel": "profile",
"payload": {
"profile": {
"key": "unique-uuid",
"name": "Jane Doe",
"title": "Senior Data Scientist",
"location": "Paris, France",
"experience_years": 6,
"summary": "3-sentence recruiter summary",
"sources": [{"type": "github", "url": "https://github.com/...", "label": "github.com/..."}],
"skills": ["Python", "NLP", "PyTorch"],
"experiences": [{"title": "...", "company": "...", "location": "Paris", "period": "2021 — 2024", "description": "..."}],
"educations": [{"degree": "...", "school": "...", "period": "..."}],
"hrflow_score": -1,
"hrflow_key": null,
"avatar_color": "#1f2937"
}
}
}'
```

---

## Stack

- **Matki** — Frontend/Backend Developer
- **Emile** — OpenClaw Integration
- **Frontend / Backend:** Next.js 16, React 19, Tailwind CSS v4, TypeScript
- **HR AI:** HrFlow.ai (parsing, scoring, Q&A, SWOT)
- **Sourcing pipeline:** trigger.dev v3
- **Outreach generation:** Mistral AI
- **Persistence:** Supabase (search history, shortlist, outreach)
- **Deploy:** Vercel
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { createClient } from "@supabase/supabase-js";
import { NextRequest, NextResponse } from "next/server";

function db() {
return createClient(
process.env.NEXT_PUBLIC_SUPABASE_URL!,
process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY!
);
}

export async function GET(req: NextRequest) {
const sessionId = req.nextUrl.searchParams.get("session_id");
if (!sessionId) return NextResponse.json({ data: [] });

const { data, error } = await db()
.from("outreach")
.select("*")
.eq("session_id", sessionId)
.order("created_at", { ascending: false })
.limit(20);

if (error) return NextResponse.json({ error: error.message }, { status: 500 });
return NextResponse.json({ data });
}

export async function DELETE(req: NextRequest) {
const body = await req.json();
const { session_id, outreach_id } = body;
if (!session_id || !outreach_id) {
return NextResponse.json({ error: "missing fields" }, { status: 400 });
}

const { error } = await db()
.from("outreach")
.delete()
.eq("session_id", session_id)
.eq("id", outreach_id);

if (error) return NextResponse.json({ error: error.message }, { status: 500 });
return NextResponse.json({ ok: true });
}
Loading
Loading