# rithesh24/ai-hiring-council architecture

> Architecture diagram of the GitHub repository rithesh24/ai-hiring-council, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-06-17). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/rithesh24/ai-hiring-council
- Repository: https://github.com/rithesh24/ai-hiring-council

## Overview

1. **Overall shape**  
This repo is a two-tier application: a **FastAPI/Python backend** that runs the hiring analysis pipeline, and a **Next.js/TypeScript frontend** that presents both a hiring dashboard and a live debate UI. The backend owns all candidate processing, LLM calls, persistence, and WebSocket event emission; the frontend is a thin real-time consumer of API and socket events.

2. **Primary data flow**  
The core flow is: **resume + job description upload → text extraction/parsing → external evidence gathering → multi-agent evaluation → debate rounds → moderator synthesis → database write → frontend display**. The analysis is not a single model call; it is a staged orchestration pipeline with explicit handoff points between services, agents, and the moderator.

3. **Backend API boundary**  
`backend/api/routes` exposes the system through REST endpoints for candidate analysis, dashboard history, debate state, and health checks, plus a WebSocket route for live updates. This is the main external boundary for the frontend. The API layer is intentionally thin and delegates work to services/orchestrators rather than embedding business logic.

4. **Candidate ingestion and evidence collection**  
`backend/services/resume_jd_parser.py`, `portfolio_scraper.py`, and `github_analyzer.py` handle the input and evidence side. The pipeline extracts structured text from uploaded resume files, parses the job description, and scans for external links. The **Evidence Agent** runs before the debate and gathers GitHub/portfolio context that is shared with all other agents, so later judgments are evidence-informed rather than isolated text-only reasoning.

5. **Agent layer**  
`backend/agents` contains six specialist evaluators plus a common base class. The agents are separated by hiring lens: technical, experience, culture, risk, growth, and problem solving. Each agent produces a score, strengths, concerns, and reasoning in Round 1 without seeing the others. The **Risk Agent** is intentionally inverted, where a higher score means lower risk, which affects how synthesis must interpret its output.

6. **Debate orchestration**  
`backend/orchestrator` is the control plane for the multi-round council. `council_graph.py`, `debate_rounds.py`, `moderator.py`, and `state_manager.py` coordinate the sequence: independent evaluation, debate exchanges, reflection, and final synthesis. This layer also enforces hard behavioral constraints such as capped score revision and prevention of self-replies, so the model outputs are not followed blindly.

7. **LLM and model routing**  
`backend/core/groq_client.py` and `model_router.py` isolate the LLM provider integration. The system uses **Groq-hosted models** for inference and performs sequential execution to avoid rate-limit collisions. Error handling includes retries/backoff and JSON parsing cleanup, which matters because the agents and moderator exchange structured outputs rather than free-form chat only.

8. **Real-time streaming path**  
`backend/services/ws_manager.py` broadcasts analysis events over WebSocket as the debate progresses. These events include round starts, individual agent speaking turns, round completion, and final decision completion. The frontend subscribes to these events to animate the 3D council chamber, update the chat feed, and drive round progress indicators in near real time.

9. **Persistence layer**  
`database/db.py`, `models.py`, and `crud.py` define a SQLite-backed audit trail for all candidate analyses. The stored record supports the dashboard’s history table, detail drawer, and summary statistics. This persistence boundary is important because it separates transient live debate state from the durable hiring history used for review later.

10. **Frontend architecture**  
The frontend is a **single-page App Router Next.js app** with two main experiences: a hiring dashboard and a live debate view. `frontend/components/dashboard` handles upload, summary cards, history, and detail inspection; `frontend/components/debate` renders the 3D council chamber, live chat, and decision banner. Hooks like `useCandidateAnalysis` and `useDebateSocket` bridge the UI to the backend REST/WebSocket surfaces.

11. **Cross-cutting utilities and runtime assumptions**  
`backend/utils` centralizes logging, text cleanup, and file handling, while the repo’s scripts package startup and model download steps. The stack is materially shaped by **FastAPI + async SQLAlchemy/aiosqlite** on the backend and **React Three Fiber/Three.js** on the frontend, because the system must support both asynchronous analysis and animated, event-driven visualization.

12. **How to draw the architecture diagram**  
The most important boxes are: **Frontend UI**, **FastAPI API/WebSocket layer**, **candidate parsing/evidence services**, **agent ensemble**, **debate orchestrator/moderator**, **Groq LLM API**, **SQLite database**, and **external sources** like GitHub and portfolio sites. The key arrows are: upload request into analysis pipeline, evidence enrichment before agent evaluation, orchestrated agent-to-agent debate, live socket events to the UI, and final results persisted to the database.

Main entry points: [`backend/services/candidate_analysis.py`](https://github.com/rithesh24/ai-hiring-council/blob/main/backend/services/candidate_analysis.py) (Analysis service), [`backend/orchestrator/council_graph.py`](https://github.com/rithesh24/ai-hiring-council/blob/main/backend/orchestrator/council_graph.py) (Council orchestrator), [`backend/services/ws_manager.py`](https://github.com/rithesh24/ai-hiring-council/blob/main/backend/services/ws_manager.py) (WS manager), [`frontend/components/debate/LiveDebate.tsx`](https://github.com/rithesh24/ai-hiring-council/blob/main/frontend/components/debate/LiveDebate.tsx) (Debate UI)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_backend["Backend"]
  node_api_boundary["FastAPI API<br/>HTTP + ws boundary<br/>[main.py]"]
  node_candidate_routes["Candidate routes<br/>rest api"]
  node_dashboard_routes["Dashboard routes<br/>rest api"]
  node_debate_routes["Debate routes<br/>rest api<br/>[debate_routes.py]"]
  node_ws_routes["WebSocket routes<br/>realtime api<br/>[ws_routes.py]"]
  node_analysis_service["Analysis service<br/>pipeline entry"]
  node_parser_service["Parsing service<br/>ingestion service"]
  node_evidence_service["Evidence service<br/>enrichment service<br/>[github_analyzer.py]"]
  node_ws_manager["WS manager<br/>event broadcaster<br/>[ws_manager.py]"]
  node_agents_cluster{{"Agent ensemble<br/>specialist evaluators<br/>[base_agent.py]"}}
  node_orchestrator["Council orchestrator<br/>debate control plane<br/>[council_graph.py]"]
  node_llm_router["Model router<br/>llm integration<br/>[model_router.py]"]
end

subgraph group_frontend["Frontend"]
  node_frontend_app["Next.js app<br/>ui shell<br/>[page.tsx]"]
  node_dashboard_ui["Dashboard UI<br/>dashboard views<br/>[Dashboard.tsx]"]
  node_debate_ui["Debate UI<br/>live debate views<br/>[LiveDebate.tsx]"]
  node_candidate_hook["Analysis hook<br/>client data hook"]
  node_socket_hook["Socket hook<br/>realtime hook<br/>[useDebateSocket.ts]"]
end

subgraph group_data["Data"]
  node_database_layer[("SQLite store<br/>persistence layer<br/>[db.py]")]
end

node_frontend_app -->|"renders"| node_dashboard_ui
node_frontend_app -->|"renders"| node_debate_ui
node_dashboard_ui -->|"requests analysis"| node_candidate_hook
node_debate_ui -->|"subscribes"| node_socket_hook
node_candidate_hook -->|"calls"| node_candidate_routes
node_socket_hook -->|"connects"| node_ws_routes
node_candidate_routes -->|"delegates"| node_analysis_service
node_dashboard_routes -->|"reads"| node_database_layer
node_debate_routes -->|"controls"| node_orchestrator
node_ws_routes -->|"uses"| node_ws_manager
node_analysis_service -->|"ingests"| node_parser_service
node_analysis_service -->|"enriches"| node_evidence_service
node_analysis_service -->|"evaluates"| node_agents_cluster
node_analysis_service -->|"orchestrates"| node_orchestrator
node_analysis_service -->|"persists"| node_database_layer
node_orchestrator -->|"calls"| node_llm_router
node_agents_cluster -->|"uses"| node_llm_router
node_orchestrator -->|"emits events"| node_ws_manager
node_evidence_service -->|"analyzes"| node_llm_router
node_ws_manager -->|"streams"| node_debate_ui
node_analysis_service -->|"publishes"| node_ws_manager

click node_frontend_app "https://github.com/rithesh24/ai-hiring-council/blob/main/frontend/app/page.tsx"
click node_dashboard_ui "https://github.com/rithesh24/ai-hiring-council/blob/main/frontend/components/dashboard/Dashboard.tsx"
click node_debate_ui "https://github.com/rithesh24/ai-hiring-council/blob/main/frontend/components/debate/LiveDebate.tsx"
click node_candidate_hook "https://github.com/rithesh24/ai-hiring-council/blob/main/frontend/hooks/useCandidateAnalysis.ts"
click node_socket_hook "https://github.com/rithesh24/ai-hiring-council/blob/main/frontend/hooks/useDebateSocket.ts"
click node_api_boundary "https://github.com/rithesh24/ai-hiring-council/blob/main/backend/main.py"
click node_candidate_routes "https://github.com/rithesh24/ai-hiring-council/blob/main/backend/api/routes/candidate_routes.py"
click node_dashboard_routes "https://github.com/rithesh24/ai-hiring-council/blob/main/backend/api/routes/dashboard_routes.py"
click node_debate_routes "https://github.com/rithesh24/ai-hiring-council/blob/main/backend/api/routes/debate_routes.py"
click node_ws_routes "https://github.com/rithesh24/ai-hiring-council/blob/main/backend/api/routes/ws_routes.py"
click node_analysis_service "https://github.com/rithesh24/ai-hiring-council/blob/main/backend/services/candidate_analysis.py"
click node_parser_service "https://github.com/rithesh24/ai-hiring-council/blob/main/backend/services/resume_jd_parser.py"
click node_evidence_service "https://github.com/rithesh24/ai-hiring-council/blob/main/backend/services/github_analyzer.py"
click node_ws_manager "https://github.com/rithesh24/ai-hiring-council/blob/main/backend/services/ws_manager.py"
click node_agents_cluster "https://github.com/rithesh24/ai-hiring-council/blob/main/backend/agents/base_agent.py"
click node_orchestrator "https://github.com/rithesh24/ai-hiring-council/blob/main/backend/orchestrator/council_graph.py"
click node_llm_router "https://github.com/rithesh24/ai-hiring-council/blob/main/backend/core/model_router.py"
click node_database_layer "https://github.com/rithesh24/ai-hiring-council/blob/main/database/db.py"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_api_boundary,node_candidate_routes,node_dashboard_routes,node_debate_routes,node_ws_routes,node_analysis_service,node_parser_service,node_evidence_service,node_ws_manager,node_agents_cluster,node_orchestrator,node_llm_router toneBlue
class node_frontend_app,node_dashboard_ui,node_debate_ui,node_candidate_hook,node_socket_hook toneAmber
class node_database_layer toneMint
```

## Components

### Backend

FastAPI app, pipeline orchestration, model access, and persistence.

- [FastAPI API](https://github.com/rithesh24/ai-hiring-council/blob/main/backend/main.py): HTTP + ws boundary · Main backend entrypoint exposing REST routes and WebSocket endpoints. · `backend/main.py`
- [Candidate routes](https://github.com/rithesh24/ai-hiring-council/blob/main/backend/api/routes/candidate_routes.py): rest api · Endpoints for starting analyses and reading candidate-focused responses. · `backend/api/routes/candidate_routes.py`
- [Dashboard routes](https://github.com/rithesh24/ai-hiring-council/blob/main/backend/api/routes/dashboard_routes.py): rest api · Endpoints for history, summaries, and dashboard data retrieval. · `backend/api/routes/dashboard_routes.py`
- [Debate routes](https://github.com/rithesh24/ai-hiring-council/blob/main/backend/api/routes/debate_routes.py): rest api · Endpoints for debate state and live council interaction. · `backend/api/routes/debate_routes.py`
- [WebSocket routes](https://github.com/rithesh24/ai-hiring-council/blob/main/backend/api/routes/ws_routes.py): realtime api · Live event stream endpoint consumed by the frontend. · `backend/api/routes/ws_routes.py`
- [Analysis service](https://github.com/rithesh24/ai-hiring-council/blob/main/backend/services/candidate_analysis.py): pipeline entry · Coordinates resume parsing, evidence gathering, debate orchestration, and persistence. · `backend/services/candidate_analysis.py`
- [Parsing service](https://github.com/rithesh24/ai-hiring-council/blob/main/backend/services/resume_jd_parser.py): ingestion service · Extracts structured text from resumes and parses job descriptions. · `backend/services/resume_jd_parser.py`
- [Evidence service](https://github.com/rithesh24/ai-hiring-council/blob/main/backend/services/github_analyzer.py): enrichment service · Collects GitHub and portfolio context before agent evaluation. · `backend/services/github_analyzer.py`
- [WS manager](https://github.com/rithesh24/ai-hiring-council/blob/main/backend/services/ws_manager.py): event broadcaster · Broadcasts round, agent, and completion events to connected clients. · `backend/services/ws_manager.py`
- [Agent ensemble](https://github.com/rithesh24/ai-hiring-council/blob/main/backend/agents/base_agent.py): specialist evaluators · Independent hiring lenses that score the candidate before and during debate. · `backend/agents/base_agent.py`
- [Council orchestrator](https://github.com/rithesh24/ai-hiring-council/blob/main/backend/orchestrator/council_graph.py): debate control plane · Coordinates round sequencing, reflection, constraints, and final synthesis. · `backend/orchestrator/council_graph.py`
- [Model router](https://github.com/rithesh24/ai-hiring-council/blob/main/backend/core/model_router.py): llm integration · Routes structured prompts to Groq-hosted models and handles retries/parsing cleanup. · `backend/core/model_router.py`

### Frontend

Next.js UI for dashboard and live debate views.

- [Next.js app](https://github.com/rithesh24/ai-hiring-council/blob/main/frontend/app/page.tsx): ui shell · App Router frontend that hosts the dashboard and live debate experience. · `frontend/app/page.tsx`
- [Dashboard UI](https://github.com/rithesh24/ai-hiring-council/blob/main/frontend/components/dashboard/Dashboard.tsx): dashboard views · Upload, history, stats, and detail inspection for past analyses. · `frontend/components/dashboard/Dashboard.tsx`
- [Debate UI](https://github.com/rithesh24/ai-hiring-council/blob/main/frontend/components/debate/LiveDebate.tsx): live debate views · 3D council chamber, chat, progress, and final decision display. · `frontend/components/debate/LiveDebate.tsx`
- [Analysis hook](https://github.com/rithesh24/ai-hiring-council/blob/main/frontend/hooks/useCandidateAnalysis.ts): client data hook · Runs candidate analysis requests and manages dashboard-side loading state. · `frontend/hooks/useCandidateAnalysis.ts`
- [Socket hook](https://github.com/rithesh24/ai-hiring-council/blob/main/frontend/hooks/useDebateSocket.ts): realtime hook · Subscribes the UI to debate events from the backend WebSocket stream. · `frontend/hooks/useDebateSocket.ts`

### Data

Durable SQLite storage for candidate analyses and history.

- [SQLite store](https://github.com/rithesh24/ai-hiring-council/blob/main/database/db.py): persistence layer · Durable audit trail for candidate analyses and dashboard history. · `database/db.py`

## Connections

- Next.js app → Dashboard UI: renders · The app hosts the dashboard experience.
- Next.js app → Debate UI: renders · The app hosts the live debate experience.
- Dashboard UI → Analysis hook: requests analysis · Dashboard interactions trigger analysis requests through the hook.
- Debate UI → Socket hook: subscribes · Debate view listens for real-time council updates.
- Analysis hook → Candidate routes: calls · Client submits analysis and fetches candidate data via REST.
- Socket hook → WebSocket routes: connects · Client attaches to the backend WebSocket event stream.
- Candidate routes → Analysis service: delegates · Route layer hands work to the analysis pipeline.
- Dashboard routes → SQLite store: reads · Dashboard endpoints query stored analysis history and summaries.
- Debate routes → Council orchestrator: controls · Debate endpoints expose the live council state.
- WebSocket routes → WS manager: uses · WebSocket endpoints are backed by the broadcast manager.
- Analysis service → Parsing service: ingests · Pipeline begins by extracting resume and job text.
- Analysis service → Evidence service: enriches · Pipeline gathers external evidence before evaluation.
- Analysis service → Agent ensemble: evaluates · Specialist agents produce scores and reasoning.
- Analysis service → Council orchestrator: orchestrates · Council workflow is coordinated by the debate control plane.
- Analysis service → SQLite store: persists · Final analysis results are written to SQLite.
- Council orchestrator → Model router: calls · Rounds and moderation invoke Groq-backed model execution.
- Agent ensemble → Model router: uses · Agents depend on the shared model routing layer.
- Council orchestrator → WS manager: emits events · Council milestones are streamed to connected clients.
- Evidence service → Model router: analyzes · Evidence gathering may use model-assisted reasoning.
- WS manager → Debate UI: streams · Live events update the 3D council and chat in the UI.
- Analysis service → WS manager: publishes · Pipeline progress is broadcast as analysis runs.
