Pick a scheduled interview and talk to Joel — a stateful AI agent (Agents SDK) that remembers the whole conversation.
JJoelidle
Select an interview above and press Start. Joel will greet the candidate and begin asking questions.
🧠 What's happening: Each message calls /api/interview/:id/reply. The same Agent instance (one Durable Object per interview) remembers every turn — no external session store. This is the Agents SDK answering Will's "Durable Objects were too hard" pain point.
🎙️ Voice Interview — talk to Joel out loud
The real voice pipeline: your mic → Whisper (speech→text) → JoelAgent (same brain) → Aura (text→speech) → Joel talks back. All on Cloudflare AI.
JJoelidle
Pick an interview and press Start. Joel will greet you out loud, then you reply with your voice.
Start the interview first
🎧 How it works: Click "Hold to talk", speak your answer, click again to stop. The recording is sent to the Worker where Whisper transcribes it, JoelAgent decides the next question, and Aura speaks the reply. Latency ~2-4s (the STT→LLM→TTS pipeline). Requires mic permission + works best in Chrome.
🎥 RTK Video — real Cloudflare WebRTC meeting
This is the genuine transport layer (the LiveKit replacement). A real WebRTC video room, provisioned via the RealtimeKit API, rendered right here.
Pick an interview and click Join. A real WebRTC meeting renders here. Tip: open this page in two tabs — candidate in one, recruiter in the other — for a real 2-way call. The RTK grid includes your own self-tile automatically.
RTK generates these natively (Workers AI) ~1-2 min after the meeting ends.
🌐 What's real here: the Worker calls the RealtimeKit API to create a meeting + mint a participant token (server-side, token never exposed). The browser joins over WebRTC through Cloudflare's global network — the same infrastructure that replaces LiveKit. Recording → R2 and AI-bot-as-participant are the documented next steps.
🔍 Smart Match — semantic candidate search
Pick a job. Vectorize + Workers AI rank candidates by meaning, not keywords.
Pick a job and click "Find best candidates".
💡 Semantic search understands that "PyTorch + NLP" means machine learning — even with zero keyword overlap with the job title.
💼 Jobs
Open positions (from D1, joined with recruiter).
Loading…
🎓 Candidates
Talent pool (from D1).
Loading…
🔒 Secure Files — R2 custom-domain workaround
Will's blocker, solved: branded, revocable download links from a private R2 bucket.
Run the steps 1→5 to see the whole flow.
✅ The bucket is never public. The Worker validates a KV token and streams from R2. Revoking deletes the token — the link dies instantly. More control than native signed URLs.
Runs a 5-step durable Workflow: load transcript → AI assessment → save to D1 → generate report → finalize. Each step is persisted and retryable.
load transcript
AI assessment
save to D1
generate report
finalize
🔁 Why a Workflow? If the AI step transiently fails, it retries (x3, exponential backoff) without re-running earlier steps. The report lands in R2; the score in D1. Track any run via /api/workflow/:instanceId.