# vijaydr29/ai-job-search-to architecture

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

- Interactive diagram: https://gitdiagram.com/vijaydr29/ai-job-search-to
- Repository: https://github.com/vijaydr29/ai-job-search-to

## Overview

1. This repository is an AI-assisted job application workflow, not a conventional app. The orchestration layer lives in Claude Code: user-facing slash commands under `.claude/commands/` drive the main flows, and reusable skill content under `.claude/skills/` stores the rules, prompts, and structured profile data Claude uses.

2. The core domain model is the candidate profile. It is persisted primarily in `CLAUDE.md` plus the structured skill files in `.claude/skills/job-application-assistant/`:
   - candidate profile and experience
   - behavioral/writing style preferences
   - job evaluation rubric
   - CV and cover-letter templates
   - interview preparation content  
   These files are the authoritative source for tailoring all outputs.

3. The main workflow boundary is split into four user actions: `/setup`, `/scrape`, `/apply`, and `/expand`, with `/upskill` as a planning/reporting extension and `/reset` as cleanup. `/setup` establishes the profile; `/scrape` searches jobs; `/apply` generates a tailored application; `/expand` enriches the profile from public sources; `/upskill` computes skill gaps and learning plans.

4. Job discovery is implemented as separate portal-specific CLI tools in `.agents/skills/`. There are four independent Danish-market integrations: Jobbank, Jobdanmark, Jobindex, and Jobnet. Each has its own `cli/` package with TypeScript source, helpers, tests, and a Bun-based runtime. This makes portal scraping an isolated subsystem rather than embedded in the Claude prompts.

5. The job search flow is: Claude’s `/scrape` command delegates to those portal CLIs, collects postings, deduplicates them, and ranks them by fit using the profile and evaluation criteria. The output is a shortlist of matches for the user to pick from, and those job records can feed directly into `/apply` or be tracked for `/upskill`.

6. The application generation flow is a drafter-reviewer pipeline. `/apply` takes either a job URL or pasted description, parses it, scores fit, drafts tailored materials, then spawns a second reviewer agent that critiques the application from a fresh context. The drafter revises based on that feedback, so the architecture intentionally separates creation from review.

7. A major technical boundary is document production. The CV and cover letter are generated as LaTeX, not plain text:
   - `cv/` contains the CV template, based on `moderncv`
   - `cover_letters/` contains a custom `cover.cls` and bundled fonts  
   The workflow compiles PDFs and inspects the rendered output, so layout correctness is part of the system design, not an afterthought.

8. The PDF verification loop is central to the repo’s architecture. The system recompiles until the CV is exactly two pages and the cover letter exactly one page, checking for layout issues like orphaned headings, font mismatches, and overflow. This means the output layer is a real feedback loop between generated LaTeX and rendered PDFs.

9. Several filesystem areas act as stateful inputs/outputs for the workflows:
   - `documents/` holds source material for onboarding and enrichment
   - `job_scraper/` stores scraper state such as seen jobs
   - `job_search_tracker.csv` tracks applications
   - `upskill/` stores learning-plan reports
   - `salary_lookup.py` and `tools/` support optional compensation benchmarking  
   These are not runtime services; they are persistent working directories and artifacts.

10. The repository has a clear separation between framework rules and user-specific content. Framework behavior lives in command files, skill definitions, and setup instructions. User-specific career data is meant to be filled into `CLAUDE.md`, the skill markdown files, and the `documents/` folder, which keeps the system portable across candidates.

11. External dependencies materially shape the architecture: Claude Code provides the agent runtime and command surface, Bun runs the Danish job-search CLIs, Python supports salary conversion/lookup tooling, and LaTeX with `lualatex`/`xelatex` is required for final document generation. The job portal integrations and salary data are intentionally pluggable rather than hard-coded to one provider.

12. Overall, the system is best diagrammed as an agent-driven pipeline with three layers: profile knowledge, job discovery, and application production. Profile data feeds both search ranking and application tailoring; job postings flow from portal CLIs into evaluation and drafting; final artifacts flow out as PDFs, tracked applications, and optional salary or upskilling reports.

Main entry points: [`.claude/commands/apply.md`](https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/commands/apply.md) (apply pipeline), [`.claude/skills/job-scraper/SKILL.md`](https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/skills/job-scraper/SKILL.md) (job shortlist), [`.claude/commands/expand.md`](https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/commands/expand.md) (scrape), [`CLAUDE.md`](https://github.com/vijaydr29/ai-job-search-to/blob/master/CLAUDE.md) (candidate profile)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_group_claude["Claude Code Orchestration"]
  node_node_claude_setup["setup<br/>slash command<br/>[setup.md]"]
  node_node_claude_scrape["scrape<br/>slash command<br/>[expand.md]"]
  node_node_claude_apply["apply<br/>slash command<br/>[apply.md]"]
  node_node_claude_expand["expand<br/>slash command<br/>[expand.md]"]
  node_node_claude_upskill["upskill<br/>skill flow<br/>[SKILL.md]"]
  node_node_claude_reset["reset<br/>cleanup command<br/>[reset.md]"]
end

subgraph group_group_profile["Candidate Knowledge"]
  node_node_profile["candidate profile<br/>core knowledge<br/>[CLAUDE.md]"]
  node_node_behavior["behavioral profile<br/>tailoring rules"]
  node_node_writing["writing style<br/>tailoring rules"]
  node_node_evaluation["job rubric<br/>scoring criteria"]
  node_node_cv_templates["CV templates<br/>latex template<br/>[05-cv-templates.md]"]
  node_node_cover_templates["cover templates<br/>latex template"]
  node_node_interview["interview prep<br/>prep content"]
end

subgraph group_group_search["Job Discovery"]
  node_node_job_skim["job shortlist<br/>ranking pipeline<br/>[SKILL.md]"]
  node_node_jobbank["Jobbank CLI<br/>portal scraper<br/>[cli.ts]"]
  node_node_jobdanmark["Jobdanmark CLI<br/>portal scraper<br/>[cli.ts]"]
  node_node_jobindex["Jobindex CLI<br/>portal scraper<br/>[cli.ts]"]
  node_node_jobnet["Jobnet CLI<br/>portal scraper<br/>[cli.ts]"]
end

subgraph group_group_apply["Application Production"]
  node_node_apply_pipeline["apply pipeline<br/>drafter-reviewer<br/>[apply.md]"]
  node_node_pdf_loop["PDF loop<br/>layout verifier<br/>[main_example.tex]"]
  node_node_cv["CV build<br/>latex production<br/>[main_example.tex]"]
  node_node_cover["cover build<br/>latex production<br/>[cover.cls]"]
end

subgraph group_group_state["Working State"]
  node_node_documents["documents<br/>working files<br/>[README.md]"]
  node_node_scraper_state[("scraper state<br/>persistent state<br/>[.gitkeep]")]
  node_node_tracker["application tracker<br/>csv ledger"]
  node_node_upskill["upskill reports<br/>report output<br/>[.gitkeep]"]
  node_node_salary["salary tools<br/>benchmarking tool<br/>[salary_lookup.py]"]
end

node_node_claude_setup -->|"establishes"| node_node_profile
node_node_claude_setup -->|"fills"| node_node_documents
node_node_claude_scrape -->|"delegates"| node_node_jobbank
node_node_claude_scrape -->|"delegates"| node_node_jobdanmark
node_node_claude_scrape -->|"delegates"| node_node_jobindex
node_node_claude_scrape -->|"delegates"| node_node_jobnet
node_node_jobbank -->|"emits"| node_node_job_skim
node_node_jobdanmark -->|"emits"| node_node_job_skim
node_node_jobindex -->|"emits"| node_node_job_skim
node_node_jobnet -->|"emits"| node_node_job_skim
node_node_profile -->|"scores"| node_node_job_skim
node_node_evaluation -->|"ranks"| node_node_job_skim
node_node_claude_apply -->|"invokes"| node_node_apply_pipeline
node_node_apply_pipeline -->|"tailors from"| node_node_profile
node_node_apply_pipeline -->|"constrains"| node_node_writing
node_node_apply_pipeline -->|"constrains"| node_node_behavior
node_node_apply_pipeline -->|"scores"| node_node_evaluation
node_node_apply_pipeline -->|"renders"| node_node_cv_templates
node_node_apply_pipeline -->|"renders"| node_node_cover_templates
node_node_apply_pipeline -->|"verifies"| node_node_pdf_loop
node_node_pdf_loop -->|"produces"| node_node_cv
node_node_pdf_loop -->|"produces"| node_node_cover
node_node_apply_pipeline -->|"records"| node_node_tracker
node_node_claude_expand -->|"enriches"| node_node_documents
node_node_claude_upskill -->|"writes"| node_node_upskill
node_node_claude_reset -->|"clears"| node_node_scraper_state
node_node_claude_reset -->|"clears"| node_node_tracker
node_node_salary -.->|"supports"| node_node_evaluation
node_node_salary -.->|"supports"| node_node_apply_pipeline
node_node_interview -->|"prepares"| node_node_apply_pipeline
node_node_profile -->|"feeds"| node_node_interview

click node_node_claude_setup "https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/commands/setup.md"
click node_node_claude_scrape "https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/commands/expand.md"
click node_node_claude_apply "https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/commands/apply.md"
click node_node_claude_expand "https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/commands/expand.md"
click node_node_claude_upskill "https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/skills/upskill/SKILL.md"
click node_node_claude_reset "https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/commands/reset.md"
click node_node_profile "https://github.com/vijaydr29/ai-job-search-to/blob/master/CLAUDE.md"
click node_node_behavior "https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/skills/job-application-assistant/02-behavioral-profile.md"
click node_node_writing "https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/skills/job-application-assistant/03-writing-style.md"
click node_node_evaluation "https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/skills/job-application-assistant/04-job-evaluation.md"
click node_node_cv_templates "https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/skills/job-application-assistant/05-cv-templates.md"
click node_node_cover_templates "https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/skills/job-application-assistant/06-cover-letter-templates.md"
click node_node_interview "https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/skills/job-application-assistant/07-interview-prep.md"
click node_node_job_skim "https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/skills/job-scraper/SKILL.md"
click node_node_jobbank "https://github.com/vijaydr29/ai-job-search-to/blob/master/.agents/skills/jobbank-search/cli/src/cli.ts"
click node_node_jobdanmark "https://github.com/vijaydr29/ai-job-search-to/blob/master/.agents/skills/jobdanmark-search/cli/src/cli.ts"
click node_node_jobindex "https://github.com/vijaydr29/ai-job-search-to/blob/master/.agents/skills/jobindex-search/cli/src/cli.ts"
click node_node_jobnet "https://github.com/vijaydr29/ai-job-search-to/blob/master/.agents/skills/jobnet-search/cli/src/cli.ts"
click node_node_apply_pipeline "https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/commands/apply.md"
click node_node_pdf_loop "https://github.com/vijaydr29/ai-job-search-to/blob/master/cv/main_example.tex"
click node_node_cv "https://github.com/vijaydr29/ai-job-search-to/blob/master/cv/main_example.tex"
click node_node_cover "https://github.com/vijaydr29/ai-job-search-to/blob/master/cover_letters/cover.cls"
click node_node_documents "https://github.com/vijaydr29/ai-job-search-to/blob/master/documents/README.md"
click node_node_scraper_state "https://github.com/vijaydr29/ai-job-search-to/blob/master/job_scraper/.gitkeep"
click node_node_tracker "https://github.com/vijaydr29/ai-job-search-to/blob/master/job_search_tracker.csv"
click node_node_upskill "https://github.com/vijaydr29/ai-job-search-to/blob/master/upskill/.gitkeep"
click node_node_salary "https://github.com/vijaydr29/ai-job-search-to/blob/master/salary_lookup.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_node_claude_setup,node_node_claude_scrape,node_node_claude_apply,node_node_claude_expand,node_node_claude_upskill,node_node_claude_reset toneBlue
class node_node_profile,node_node_behavior,node_node_writing,node_node_evaluation,node_node_cv_templates,node_node_cover_templates,node_node_interview toneAmber
class node_node_job_skim,node_node_jobbank,node_node_jobdanmark,node_node_jobindex,node_node_jobnet toneMint
class node_node_apply_pipeline,node_node_pdf_loop,node_node_cv,node_node_cover toneRose
class node_node_documents,node_node_scraper_state,node_node_tracker,node_node_upskill,node_node_salary toneIndigo
```

## Components

### Claude Code Orchestration

User-facing commands and reusable skill prompts that drive the workflow.

- [setup](https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/commands/setup.md): slash command · Initializes the candidate profile and workspace. · `.claude/commands/setup.md`
- [scrape](https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/commands/expand.md): slash command · Searches jobs through portal integrations and ranks matches. · `.claude/commands/expand.md`
- [apply](https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/commands/apply.md): slash command · Generates tailored application materials for a selected job. · `.claude/commands/apply.md`
- [expand](https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/commands/expand.md): slash command · Enriches the profile from public sources and documents. · `.claude/commands/expand.md`
- [upskill](https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/skills/upskill/SKILL.md): skill flow · Computes skill gaps and learning-plan reports. · `.claude/skills/upskill/SKILL.md`
- [reset](https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/commands/reset.md): cleanup command · Clears workflow state and tracked artifacts. · `.claude/commands/reset.md`

### Candidate Knowledge

Authoritative profile data and tailoring rules used across search and application steps.

- [candidate profile](https://github.com/vijaydr29/ai-job-search-to/blob/master/CLAUDE.md): core knowledge · Primary candidate facts, experience, and positioning data. · `CLAUDE.md`
- [behavioral profile](https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/skills/job-application-assistant/02-behavioral-profile.md): tailoring rules · Writing and behavioral preferences used to shape output. · `.claude/skills/job-application-assistant/02-behavioral-profile.md`
- [writing style](https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/skills/job-application-assistant/03-writing-style.md): tailoring rules · Style constraints for generated application text. · `.claude/skills/job-application-assistant/03-writing-style.md`
- [job rubric](https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/skills/job-application-assistant/04-job-evaluation.md): scoring criteria · Fit criteria used to rank jobs and score applications. · `.claude/skills/job-application-assistant/04-job-evaluation.md`
- [CV templates](https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/skills/job-application-assistant/05-cv-templates.md): latex template · ModernCV-based resume templates and layout rules. · `.claude/skills/job-application-assistant/05-cv-templates.md`
- [cover templates](https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/skills/job-application-assistant/06-cover-letter-templates.md): latex template · Cover-letter templates and class conventions. · `.claude/skills/job-application-assistant/06-cover-letter-templates.md`
- [interview prep](https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/skills/job-application-assistant/07-interview-prep.md): prep content · Interview preparation content derived from the profile. · `.claude/skills/job-application-assistant/07-interview-prep.md`

### Job Discovery

Portal-specific scrapers and the shortlist/ranking flow for job matching.

- [job shortlist](https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/skills/job-scraper/SKILL.md): ranking pipeline · Deduplicates and ranks discovered jobs by profile fit. · `.claude/skills/job-scraper/SKILL.md`
- [Jobbank CLI](https://github.com/vijaydr29/ai-job-search-to/blob/master/.agents/skills/jobbank-search/cli/src/cli.ts): portal scraper · Bun-based integration for Jobbank postings. · `.agents/skills/jobbank-search/cli/src/cli.ts`
- [Jobdanmark CLI](https://github.com/vijaydr29/ai-job-search-to/blob/master/.agents/skills/jobdanmark-search/cli/src/cli.ts): portal scraper · Bun-based integration for Jobdanmark postings. · `.agents/skills/jobdanmark-search/cli/src/cli.ts`
- [Jobindex CLI](https://github.com/vijaydr29/ai-job-search-to/blob/master/.agents/skills/jobindex-search/cli/src/cli.ts): portal scraper · Bun-based integration for Jobindex postings. · `.agents/skills/jobindex-search/cli/src/cli.ts`
- [Jobnet CLI](https://github.com/vijaydr29/ai-job-search-to/blob/master/.agents/skills/jobnet-search/cli/src/cli.ts): portal scraper · Bun-based integration for Jobnet postings. · `.agents/skills/jobnet-search/cli/src/cli.ts`

### Application Production

Draft-review-generation pipeline and PDF verification for CVs and cover letters.

- [apply pipeline](https://github.com/vijaydr29/ai-job-search-to/blob/master/.claude/commands/apply.md): drafter-reviewer · Parses jobs, scores fit, drafts, reviews, and revises applications. · `.claude/commands/apply.md`
- [PDF loop](https://github.com/vijaydr29/ai-job-search-to/blob/master/cv/main_example.tex): layout verifier · Rebuilds documents until page counts and layout constraints are correct. · `cv/main_example.tex`
- [CV build](https://github.com/vijaydr29/ai-job-search-to/blob/master/cv/main_example.tex): latex production · Generates the final CV PDF from LaTeX. · `cv/main_example.tex`
- [cover build](https://github.com/vijaydr29/ai-job-search-to/blob/master/cover_letters/cover.cls): latex production · Generates the final cover letter PDF from LaTeX. · `cover_letters/cover.cls`

### Working State

Persistent inputs, outputs, and operational artifacts used by the workflows.

- [documents](https://github.com/vijaydr29/ai-job-search-to/blob/master/documents/README.md): working files · Source material for onboarding, enrichment, and generated artifacts. · `documents/README.md`
- [scraper state](https://github.com/vijaydr29/ai-job-search-to/blob/master/job_scraper/.gitkeep): persistent state · Seen-job and scraper working state. · `job_scraper/.gitkeep`
- [application tracker](https://github.com/vijaydr29/ai-job-search-to/blob/master/job_search_tracker.csv): csv ledger · Tracks submitted and planned applications. · `job_search_tracker.csv`
- [upskill reports](https://github.com/vijaydr29/ai-job-search-to/blob/master/upskill/.gitkeep): report output · Stores skill-gap and learning-plan outputs. · `upskill/.gitkeep`
- [salary tools](https://github.com/vijaydr29/ai-job-search-to/blob/master/salary_lookup.py): benchmarking tool · Optional compensation lookup and conversion support. · `salary_lookup.py`

## Connections

- setup → candidate profile: establishes · Creates the authoritative candidate profile.
- setup → documents: fills · Seeds onboarding and source documents.
- scrape → Jobbank CLI: delegates · Queries one portal integration.
- scrape → Jobdanmark CLI: delegates · Queries one portal integration.
- scrape → Jobindex CLI: delegates · Queries one portal integration.
- scrape → Jobnet CLI: delegates · Queries one portal integration.
- Jobbank CLI → job shortlist: emits · Contributes job records for deduping and ranking.
- Jobdanmark CLI → job shortlist: emits · Contributes job records for deduping and ranking.
- Jobindex CLI → job shortlist: emits · Contributes job records for deduping and ranking.
- Jobnet CLI → job shortlist: emits · Contributes job records for deduping and ranking.
- candidate profile → job shortlist: scores · Provides fit context for ranking.
- job rubric → job shortlist: ranks · Supplies the rubric for shortlist ordering.
- apply → apply pipeline: invokes · Starts application generation.
- apply pipeline → candidate profile: tailors from · Uses candidate facts and experience.
- apply pipeline → writing style: constrains · Applies voice and style preferences.
- apply pipeline → behavioral profile: constrains · Applies behavioral preferences.
- apply pipeline → job rubric: scores · Evaluates job fit before drafting.
- apply pipeline → CV templates: renders · Builds CV content in template form.
- apply pipeline → cover templates: renders · Builds cover-letter content in template form.
- apply pipeline → PDF loop: verifies · Checks layout and page-count constraints.
- PDF loop → CV build: produces · Iterates until CV is exactly two pages.
- PDF loop → cover build: produces · Iterates until cover letter is exactly one page.
- apply pipeline → application tracker: records · Adds application tracking metadata.
- expand → documents: enriches · Pulls in public-source material.
- upskill → upskill reports: writes · Outputs learning-plan reports.
- reset → scraper state: clears · Resets scraper working state.
- reset → application tracker: clears · Clears tracked application records.
- salary tools → job rubric: supports · Optional compensation context can inform decisions.
- salary tools → apply pipeline: supports · Optional salary benchmarking can inform targeting.
- interview prep → apply pipeline: prepares · Feeds interview-focused follow-up content.
- candidate profile → interview prep: feeds · Supplies interview prep material.
