Skip to content
UpthenaPublic

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

13 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 

Repository files navigation

MeritOS

AI-powered candidate screening for recruiters. Automate first-round interviews, get structured reports, and focus on the best fits.


Overview

MeritOS lets recruiters:

  1. Create roles — Paste a job description and optionally describe what to cover in plain English
  2. AI-generated interview plans — GPT-4o produces a structured question flow; recruiters can edit before deploying
  3. Share one link per role — Candidates complete the screening on their own schedule (voice or avatar mode)
  4. Review results — See completions and reports in the recruiter dashboard

System Architecture

flowchart TB
    subgraph frontend ["Web App (Vite + React)"]
        Landing[Landing Page]
        Dash[Dashboard]
        RoleNew[Create Role]
        RoleDetail[Role Detail]
        TemplateSetup[Template Editor]
        CandEntry[Candidate Entry /i/:slug]
        InterviewRoom[LiveKit Room]
        SessionReview[Session Report]
    end

    subgraph convex ["Convex Backend"]
        Roles[roles.*]
        Templates[templates.*]
        Sessions[sessions.* / sessionActions.*]
        Candidates[candidates.*]
        Reports[reports.* / reportHttp.*]
        GenPlan[generatePlan]
        HTTP[http.ts router]
    end

    subgraph agent ["Python Agent (LiveKit)"]
        LiveKitAgent[Agent entrypoint]
        FetchTemplate[GET template via HTTP]
        Conduct[Conduct interview]
        AvatarOrVoice[Voice-only or Avatar]
    end

    subgraph external [External Services]
        OpenAI[OpenAI GPT-4o]
        LiveKit[LiveKit Cloud]
        ElevenLabs[ElevenLabs TTS]
        Bey[Beyond Presence Avatar]
    end

    Dash --> Roles
    RoleNew --> GenPlan
    GenPlan --> OpenAI
    RoleNew --> Templates
    RoleDetail --> Sessions
    TemplateSetup --> Templates
    CandEntry --> Sessions
    CandEntry --> InterviewRoom
    InterviewRoom --> LiveKit
    SessionReview --> Reports

    LiveKitAgent --> LiveKit
    LiveKitAgent --> FetchTemplate
    FetchTemplate --> HTTP
    HTTP --> Sessions
    HTTP --> Templates
    LiveKitAgent --> Conduct
    Conduct --> AvatarOrVoice
    AvatarOrVoice --> ElevenLabs
    AvatarOrVoice --> Bey
Loading

Project Structure

upthena/
├── apps/
│   ├── web/              # Vite + React frontend
│   │   └── src/
│   │       ├── pages/    # Route pages (Dashboard, RoleNew, RoleDetail, etc.)
│   │       └── components/
│   │           └── Interview/InterviewRoom.tsx   # LiveKit room component
│   └── agent/            # Python LiveKit agent (AI interviewer)
│       ├── main.py       # Agent entrypoint
│       ├── convex_client.py  # HTTP client for Convex
│       └── Dockerfile
├── packages/
│   └── db/               # Convex backend
│       └── convex/
│           ├── schema.ts             # Data model
│           ├── roles.ts              # Role CRUD
│           ├── templates.ts          # Interview template CRUD
│           ├── sessions.ts           # Session creation (candidate flow)
│           ├── sessionActions.ts     # LiveKit room + token (Node action)
│           ├── sessionMutations.ts   # Internal: mark started/completed
│           ├── candidates.ts         # Candidate management
│           ├── reports.ts            # Report queries
│           ├── reportHttp.ts         # HTTP endpoint for agent report submission
│           ├── reportMutations.ts    # Internal report creation
│           ├── interviewTemplateHttp.ts  # HTTP endpoint for agent template fetch
│           ├── generatePlan.ts       # GPT-4o interview plan generation
│           ├── http.ts               # HTTP router
│           └── lib/devUser.ts        # Dev-mode user helper
└── README.md

Data Model

Table Purpose
users Recruiter profiles (dev-mode single user for now)
roles Job positions with shareable slug, status, optional deadline
interviewTemplates Per-role config: sections, questions, persona, duration, voice/avatar mode
candidates People who take interviews (name, email, status)
interviewSessions LiveKit sessions linking role + candidate + template
reports Post-interview summaries and scores

Quick Start

You need three services running: Convex backend, web app, and the Python agent.

Prerequisites

1. Convex Backend

cd packages/db
npm install
npx convex dev          # starts local dev server, deploys schema

Set required environment variables in your Convex dashboard (or via CLI):

npx convex env set OPENAI_API_KEY "sk-..."
npx convex env set LIVEKIT_URL "wss://your-url.livekit.cloud"
npx convex env set LIVEKIT_API_KEY "your-key"
npx convex env set LIVEKIT_API_SECRET "your-secret"
# Optional: shared secret for agent report submission
npx convex env set CONVEX_AGENT_SECRET "some-secret"

2. Web App

cd apps/web
cp .env.example .env
# Fill in: VITE_CONVEX_URL, VITE_LIVEKIT_URL
npm install
npm run dev

Opens at http://localhost:8080.

3. Python Agent

cd apps/agent
cp .env.example .env
# Fill in: LIVEKIT_URL, LIVEKIT_API_KEY, LIVEKIT_API_SECRET,
#          ELEVEN_API_KEY, ELEVEN_VOICE_ID, OPENAI_API_KEY,
#          CONVEX_SITE_URL
# Optional: BEY_API_KEY, BEY_AVATAR_ID (for avatar mode)
pip install -r requirements.txt
python main.py dev

4. Test the Flow

  1. Go to http://localhost:8080/dashboard
  2. Click Add Role, paste a job description, generate the plan
  3. Edit the template if needed, then Activate the role
  4. Copy the candidate link (/i/:slug) and open in a new tab
  5. Enter name + email, click Start interview
  6. The AI agent conducts the screening (ensure the agent is running)
  7. Back in the dashboard, view the session under the role

Environment Variables

App Variable Required Purpose
Convex OPENAI_API_KEY Yes Interview plan generation (GPT-4o)
Convex LIVEKIT_URL Yes LiveKit room creation
Convex LIVEKIT_API_KEY Yes LiveKit auth
Convex LIVEKIT_API_SECRET Yes LiveKit auth
Convex CONVEX_AGENT_SECRET No Shared secret for agent HTTP endpoints
Web VITE_CONVEX_URL Yes Convex client URL
Web VITE_LIVEKIT_URL Yes LiveKit WebSocket URL
Agent LIVEKIT_URL Yes LiveKit connection
Agent LIVEKIT_API_KEY Yes LiveKit auth
Agent LIVEKIT_API_SECRET Yes LiveKit auth
Agent OPENAI_API_KEY Yes STT + LLM (GPT-4o-mini)
Agent ELEVEN_API_KEY Yes ElevenLabs TTS
Agent ELEVEN_VOICE_ID Yes Voice selection
Agent CONVEX_SITE_URL Yes Convex HTTP API base
Agent BEY_API_KEY No Beyond Presence avatar
Agent BEY_AVATAR_ID No Avatar selection
Agent CONVEX_AGENT_SECRET No Must match Convex if set

Deployment

Component Options
Web Vercel, Netlify, or any static host (npm run build)
Convex npx convex deploy
Agent Docker on Fly.io, Railway, or similar (see apps/agent/Dockerfile)

Current Assumptions & Limitations

This is an early version. The following are known constraints and decisions:

Authentication

  • No real auth. There is no Auth0/Clerk/OAuth integration. The recruiter dashboard uses a hardcoded dev user (authSubject: "dev"). ProtectedRoute is a passthrough.
  • Candidate flow is intentionally unauthenticated (name + email only).

Interview Templates

  • Templates are generated from a plain-text job description via GPT-4o. There is no option to upload PDFs, LinkedIn profiles, or structured job specs.
  • The template editor is functional but minimal — section/question editing only, no drag-and-drop reordering or adding/removing sections from the UI.

Reports

  • Reports are not yet generated by the agent. The infrastructure exists (HTTP endpoint, Convex mutations, report page), but the agent does not call submit_report() after the interview. A placeholder report is created when the session ends.
  • The report page shows a summary field only — no per-section scores, transcript, or recording.

Interview Agent

  • The agent uses GPT-4o-mini for conversation and ElevenLabs for TTS. There is no pluggable model selection.
  • Avatar mode requires a Beyond Presence account. Without it, the agent falls back to voice-only.
  • The agent does not enforce a hard time limit — it relies on the LLM following the duration instruction.

Integrations

  • No ATS integration (Greenhouse, Lever, etc.). Candidates are tracked internally only.
  • No email notifications. Recruiters must manually share the candidate link; candidates are not emailed.
  • No recording/playback. Sessions are not recorded.

Infrastructure

  • Convex is used as the backend (not Supabase/Postgres). All data, mutations, and server-side logic live in Convex functions.
  • There is no root package.json or monorepo tooling (Turborepo, Nx). Each app is run independently.
  • The web app depends on livekit-client and @livekit/components-react v2 for the interview room.

UI/UX

  • Landing page, demo page, and sign-in page exist but are placeholders for a future marketing site.
  • The dashboard is role-centric — there is no global candidate list or cross-role analytics.
  • Dark mode is supported via CSS variables but there is no theme toggle in the UI.

License

Private — all rights reserved.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages