# alumnx-ai-labs/langgraph-job-agent architecture

> Architecture diagram of the GitHub repository alumnx-ai-labs/langgraph-job-agent, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-09-30). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/alumnx-ai-labs/langgraph-job-agent
- Repository: https://github.com/alumnx-ai-labs/langgraph-job-agent

## Overview

This repository is a deterministic LangGraph job-description intake workflow, exposed through both a Flask chat UI and a CLI. Recruiters submit a JD; the graph extracts required fields, pauses for missing information, checks duplicates, scores and may rewrite the description, then publishes, rejects duplicates, or escalates when a retry limit is reached. Gemini provides extraction, scoring, and rewriting; MongoDB stores and checks postings, while SQLite checkpoints support pause/resume. The README documents these stages and branches; the shown excerpts confirm key calls, though graph construction and several node bodies are only partially shown.

Main entry points: [`jd_intake_pipeline.py`](https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/jd_intake_pipeline.py) (Quality scoring), [`app.py`](https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/app.py) (Flask chat), [`jobs_db.py`](https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/jobs_db.py) (Database access), [`templates/index.html`](https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/templates/index.html) (Chat frontend)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_interfaces["Recruiter interfaces"]
  node_flask["Flask chat<br/>[app.py]"]
  node_chat_ui["Chat frontend<br/>[index.html]"]
  node_cli["CLI runner"]
end

subgraph group_workflow["Intake workflow"]
  node_graph["Workflow graph"]
  node_extract["Field extraction"]
  node_missing["Missing info"]
  node_duplicate["Duplicate check"]
  node_quality["Quality scoring"]
  node_rewrite["JD rewriting"]
  node_publish["Publish step"]
  node_reject["Duplicate rejection"]
  node_escalate["Human escalation"]
end

subgraph group_persistence["Persistence"]
  node_mongo[("MongoDB jobs")]
  node_jobs_db["Database access<br/>[jobs_db.py]"]
  node_checkpoint[("SQLite checkpoints<br/>[app.py]")]
end

node_recruiter(("Recruiter"))
node_gemini["Gemini API"]

node_recruiter -->|"submits JD"| node_chat_ui
node_chat_ui -->|"sends chat"| node_flask
node_flask -->|"invokes or resumes"| node_graph
node_recruiter -->|"submits JD"| node_cli
node_cli -->|"invokes or resumes"| node_graph
node_graph -->|"dispatches"| node_extract
node_extract -->|"invokes"| node_gemini
node_extract -->|"routes if incomplete"| node_missing
node_extract -->|"routes if complete"| node_duplicate
node_missing -->|"asks next field"| node_missing
node_missing -->|"routes when complete"| node_duplicate
node_missing -->|"routes at limit"| node_escalate
node_duplicate -->|"looks up posting"| node_jobs_db
node_jobs_db -->|"queries or inserts"| node_mongo
node_duplicate -->|"routes if found"| node_reject
node_duplicate -->|"routes if unique"| node_quality
node_quality -->|"invokes"| node_gemini
node_quality -->|"routes at threshold"| node_publish
node_quality -->|"routes below threshold"| node_rewrite
node_rewrite -->|"invokes"| node_gemini
node_rewrite -->|"returns for rescoring"| node_quality
node_quality -->|"routes at revision cap"| node_escalate
node_publish -->|"writes posting"| node_jobs_db
node_flask -->|"persists thread state"| node_checkpoint
node_cli -->|"resumes saved thread"| node_checkpoint

click node_flask "https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/app.py"
click node_chat_ui "https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/templates/index.html"
click node_cli "https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/jd_intake_pipeline.py"
click node_graph "https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/jd_intake_pipeline.py"
click node_extract "https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/jd_intake_pipeline.py"
click node_missing "https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/jd_intake_pipeline.py"
click node_duplicate "https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/jd_intake_pipeline.py"
click node_quality "https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/jd_intake_pipeline.py"
click node_rewrite "https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/jd_intake_pipeline.py"
click node_publish "https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/jd_intake_pipeline.py"
click node_reject "https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/jd_intake_pipeline.py"
click node_escalate "https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/jd_intake_pipeline.py"
click node_jobs_db "https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/jobs_db.py"
click node_checkpoint "https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/app.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_flask,node_chat_ui,node_cli toneBlue
class node_graph,node_extract,node_missing,node_duplicate,node_quality,node_rewrite,node_publish,node_reject,node_escalate toneAmber
class node_mongo,node_jobs_db,node_checkpoint,node_gemini toneMint
class node_recruiter toneIndigo
```

## Components

### Recruiter interfaces

- [Flask chat](https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/app.py): `app.py`
- [Chat frontend](https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/templates/index.html): `templates/index.html`
- [CLI runner](https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/jd_intake_pipeline.py): `jd_intake_pipeline.py`

### Intake workflow

- [Workflow graph](https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/jd_intake_pipeline.py): `jd_intake_pipeline.py`
- [Field extraction](https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/jd_intake_pipeline.py): `jd_intake_pipeline.py`
- [Missing info](https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/jd_intake_pipeline.py): `jd_intake_pipeline.py`
- [Duplicate check](https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/jd_intake_pipeline.py): `jd_intake_pipeline.py`
- [Quality scoring](https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/jd_intake_pipeline.py): `jd_intake_pipeline.py`
- [JD rewriting](https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/jd_intake_pipeline.py): `jd_intake_pipeline.py`
- [Publish step](https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/jd_intake_pipeline.py): `jd_intake_pipeline.py`
- [Duplicate rejection](https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/jd_intake_pipeline.py): `jd_intake_pipeline.py`
- [Human escalation](https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/jd_intake_pipeline.py): `jd_intake_pipeline.py`

### Persistence

- **MongoDB jobs**
- [Database access](https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/jobs_db.py): `jobs_db.py`
- [SQLite checkpoints](https://github.com/alumnx-ai-labs/langgraph-job-agent/blob/main/app.py): `app.py`

### Other components

- **Recruiter**
- **Gemini API**

## Connections

- Recruiter → Chat frontend: submits JD (evidence: `README.md`)
- Chat frontend → Flask chat: sends chat (evidence: `README.md`)
- Flask chat → Workflow graph: invokes or resumes (evidence: `app.py`)
- Recruiter → CLI runner: submits JD (evidence: `README.md`)
- CLI runner → Workflow graph: invokes or resumes (evidence: `jd_intake_pipeline.py`)
- Workflow graph → Field extraction: dispatches (evidence: `README.md`)
- Field extraction → Gemini API: invokes (evidence: `jd_intake_pipeline.py`)
- Field extraction → Missing info: routes if incomplete (evidence: `jd_intake_pipeline.py`)
- Field extraction → Duplicate check: routes if complete (evidence: `jd_intake_pipeline.py`)
- Missing info → Missing info: asks next field (evidence: `README.md`)
- Missing info → Duplicate check: routes when complete (evidence: `jd_intake_pipeline.py`)
- Missing info → Human escalation: routes at limit (evidence: `jd_intake_pipeline.py`)
- Duplicate check → Database access: looks up posting (evidence: `jd_intake_pipeline.py`)
- Database access → MongoDB jobs: queries or inserts (evidence: `jobs_db.py`)
- Duplicate check → Duplicate rejection: routes if found (evidence: `README.md`)
- Duplicate check → Quality scoring: routes if unique (evidence: `README.md`)
- Quality scoring → Gemini API: invokes (evidence: `jd_intake_pipeline.py`)
- Quality scoring → Publish step: routes at threshold (evidence: `README.md`)
- Quality scoring → JD rewriting: routes below threshold (evidence: `README.md`)
- JD rewriting → Gemini API: invokes (evidence: `jd_intake_pipeline.py`)
- JD rewriting → Quality scoring: returns for rescoring (evidence: `README.md`)
- Quality scoring → Human escalation: routes at revision cap (evidence: `README.md`)
- Publish step → Database access: writes posting (evidence: `README.md`)
- Flask chat → SQLite checkpoints: persists thread state (evidence: `app.py`)
- CLI runner → SQLite checkpoints: resumes saved thread (evidence: `README.md`)
