Interviewer is a Proof of Concept AI-powered interview practice application designed to help a candidate prepare for real job interviews through voice enabled mock sessions. Built on the principle of local-first privacy, it runs entirely on your own hardware. No data ever leaves your machine, no API keys required, no subscription fees.
The application generates dynamic, context aware interviewer personas based on actual job descriptions and your resume, conducts multi phase technical and behavioral interviews with real time voice interaction, and provides comprehensive, actionable feedback to help you improve.
- We are open to community contributions.
- Tested on the Strix Halo with 128GB RAM.
- Recommended Models: Qwen3-Coder-30B-A3B-Instruct-GGUF
- Voice-Enabled Interviews - Realistic interview simulation with speech-to-text (ASR) and text-to-speech (TTS)
- Local AI Models - Runs entirely on your hardware via Lemonade Server—no cloud dependencies
- Smart Document Extraction - AI powered parsing of resumes and job descriptions
- Dynamic Persona Generation - Creates tailored interviewer personas based on job/role
- Comprehensive Feedback - Detailed performance analysis with actionable insights
- Privacy-First - All data stored locally in JSON format
- Cross-Platform Desktop App - Electron based for Windows, macOS, and Linux
git clone https://github.com/lemonade-sdk/interviewer.git
cd interviewer
# Install Node.js dependencies
npm installFollow the Lemonade Server installation guide to set up local LLM inference.
# Windows / macOS
npm run dev
# Linux / Ubuntu
npm run dev:linux
# In a separate terminal, ensure Lemonade Server is running
lemonade-server# Build React app
npm run build
# Build Electron app for distribution
npm run build:electron# TypeScript tests
npm test┌─────────────────────────────────────────────────────────────┐
│ INTERVIEWER APP │
├─────────────────────────────────────────────────────────────┤
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────┐ │
│ │ Electron │ │ React │ │ TypeScript │ │
│ │ (Main) │ │ (UI) │ │ Services │ │
│ └──────┬──────┘ └──────┬──────┘ └────────┬────────┘ │
│ │ │ │ │
│ └────────────────┴───────────────────┘ │
│ │ │
│ ┌───────────────────────┼───────────────────────────┐ │
│ │ UNIFIED PROMPT SYSTEM │ │
│ │ ┌─────────────────┐ ┌─────────────────────┐ │ │
│ │ │ prompts.json │ │ StructuredExtraction│ │ │
│ │ │ • 5 interview │ │ • Document parsing │ │ │
│ │ │ phases │ │ • Job extraction │ │ │
│ │ │ • Persona gen │ │ • Feedback extract │ │ │
│ │ │ • Feedback │ │ │ │ │
│ │ └─────────────────┘ └─────────────────────┘ │ │
│ └───────────────────────┼───────────────────────────┘ │
│ │ │
│ ┌───────────────────────┼───────────────────────────┐ │
│ │ PHASE-AWARE INTERVIEW FLOW │ │
│ │ Greeting → Q1 → Q2 → Q3 → Wrap-up │ │
│ │ Audio check → Self-Intro → Core Qs → Closing │ │
│ └───────────────────────┼───────────────────────────┘ │
│ │ │
└──────────────────────────┼────────────────────────────────┘
│
┌────────────┴────────────┐
│ Lemonade Server │
│ (Local LLM Inference) │
│ • LLM (llama.cpp) │
│ • ASR (Whisper) │
│ • TTS (Kokoro) │
└─────────────────────────┘
interviewer/
├── src/
│ ├── services/ # Core business logic
│ │ ├── InterviewService.ts # Interview orchestration
│ │ ├── LemonadeClient.ts # LLM/AI API client
│ │ ├── PromptManager.ts # Prompt template management
│ │ ├── PersonaGeneratorService.ts # Dynamic persona creation
│ │ ├── StructuredExtractionService.ts # Data extraction
│ │ └── audio/ # TTS, ASR, VAD services
│ ├── data/
│ │ └── prompts.json # Unified prompts (phases, persona, feedback)
│ ├── database/ # JSON-based storage layer
│ ├── types/ # TypeScript definitions
│ ├── ui/ # React components
│ └── electron_app/ # Electron main process
├── docs/ # Documentation
└── tests/ # Test suites
- Framework: React 18 + TypeScript
- Desktop: Electron
- Build: Vite
- Styling: Tailwind CSS
- State: Zustand
- LLM: Llama.cpp via Lemonade Server
- ASR: Whisper (speech-to-text)
- TTS: Kokoro (text-to-speech)
- Inference: Vulkan/ROCm/CUDA/CPU backends
- HTTP: OpenAI client + Axios for Lemonade Server
The interview follows a strict 5-phase structure with exactly 5 dynamically generated core question topics (Q1–Q5). All phases and questions are controlled by the unified prompt system in prompts.json.
| Phase | Focus | Description |
|---|---|---|
| 1. Greeting | Audio check + Introduction | One-time audio check, persona self-introduction, session overview (duration + format) |
| 2. Q1 Active | Warm-up / Baseline | Open rapport-building question + light follow-ups |
| 3. Q2 Active | Core Technical | Job-specific technical depth probes |
| 4. Q3 Active | Behavioral / Leadership | STAR-method behavioral questions + leadership signals |
| 5. Wrap-up | Closing + Candidate Questions | Summary, feedback preview, open Q&A from candidate |
- Total structured questions: 5 main questions (Q1–Q5) with adaptive, context-aware follow-up probes.
- Question topics (
q1Topic…q5Topic) and "watch signals" (resume gaps, red flags, etc.) are generated fresh every session from your JD + resume.
- Persona Generation: Creates tailored 21+ field interviewer personas from job/resume
- Document Extraction: Parses resumes and job descriptions for context
- Comprehensive Feedback: Multi-stage analysis with structured Q&A grading
The interview logic, persona generation, phase gating, and structured output are powered by src/data/prompts.json, which implements Universal Conditional Logic (UCL) — a formal mathematical framework for prompt optimization authored by the same developer.
This project is a real-world application of UCL for multi-turn, voice-interactive, agentic interview simulation.
┌─────────────┐ ┌─────────────┐ ┌─────────────────┐
│ Document │ │ Persona │ │ Interview │
│ Upload │ → │ Generation │ → │ Session │
└─────────────┘ └─────────────┘ └─────────────────┘
│ │
↓ ↓
┌─────────────┐ ┌─────────────────┐
│ Extract │ │ 5 Phases │
│ Job/Resume │ │ Dynamic Flow │
└─────────────┘ └─────────────────┘
│
↓
┌─────────────────┐
│ Feedback │
│ Generation │
└─────────────────┘
The app runs on Ubuntu out of the box. A few things to be aware of:
- Use
npm run dev:linuxinstead ofnpm run dev— this passes the required--no-sandboxflag to Electron, bypassing the SUID sandbox requirement that causes a crash on most Linux setups. - The default model (
Qwen3-Coder-30B-A3B-Instruct-GGUF) is set automatically. If you previously ran an older version that saved a different model name (e.g.gpt-oss-mxp4), the app will auto-correct it on next startup. - For packaged AppImage builds, no extra flags are needed — the sandbox is handled at the app level.
- Fork the repository
- Create a feature branch:
git checkout -b feature/amazing-feature - Make your changes
- Run tests and linting
- Commit:
git commit -m 'feat: add amazing feature' - Push:
git push origin feature/amazing-feature - Open a Pull Request
This project is licensed under the MIT License - see the LICENSE file for details.
- Lemonade Server - Unified local AI inference
- llama.cpp - Efficient LLM inference
- Whisper - OpenAI's ASR model
- Kokoro - Fast TTS
- Anthony Mikinka. "Universal Conditional Logic: A Formal Language for Prompt Engineering." arXiv:2601.00880 (2025). https://arxiv.org/abs/2601.00880 · GitHub
Made with ❤️ for better, private interview preparation
