# Main Architectural Components of the AI Job Search System: Thin-Pointer Architecture Explained

> Explore the main architectural components of the ai-job-search system. Discover its thin-pointer architecture for a local, autonomous job application pipeline.

- Repository: [Mads Lorentzen/ai-job-search](https://github.com/MadsLorentzen/ai-job-search)
- Tags: architecture
- Published: 2026-07-25

---

**The ai-job-search repository implements a thin-pointer architecture that separates declarative specifications in [`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md) from executable portal-specific CLI tools, enabling a fully local, autonomous job application pipeline.**

The ai-job-search system is an open-source framework by MadsLorentzen that automates the entire job search workflow using Claude Code. Its architecture follows a **thin-pointer design pattern**, where workflow logic lives in markdown specifications while external tools handle data extraction and document generation. This separation allows users to customize behavior by editing text files rather than source code.

## Core Configuration: The CLAUDE.md Profile

At the heart of the system sits **[`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md)**, the single source of truth for all agents.

This file stores the candidate's personal data, career goals, and high-level workflow rules that drive every subsequent operation. When you invoke commands like `/setup` or `/apply`, Claude Code reads this file to understand the user's context, writing style, and evaluation criteria.

Located at the repository root, [`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md) acts as the declarative specification that all other components reference. According to the source code, this is the *only* place where candidate-specific workflow logic resides, making the system portable and version-controllable.

## Command Interface Layer

The **`.claude/commands/`** directory defines the CLI-style interface that users interact with.

Each command is implemented as a standalone markdown file (e.g., [`setup.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/setup.md), [`apply.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/apply.md), [`scrape.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/scrape.md)) containing the prompts and instructions Claude Code executes when you type `/setup`, `/scrape`, or `/apply`. This design makes the command layer entirely transparent and editable without touching TypeScript or Python code.

Key commands include:

- **`/setup`** – Populates [`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md) and initializes the `documents/` folder
- **`/scrape`** – Invokes portal CLI tools to collect job postings
- **`/apply`** – Evaluates fit, drafts LaTeX documents, and compiles PDFs
- **`/interview`** – Prepares interview materials based on job context

## Domain Knowledge Engine

The **`.claude/skills/job-application-assistant/`** directory encodes the system's domain expertise.

This skill is broken into numbered markdown sections (including [`SKILL.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/SKILL.md)) that cover:
- Candidate profile interpretation
- Writing style guidelines
- Job evaluation frameworks
- CV and cover letter templates
- Interview preparation protocols

When processing applications, Claude Code loads these files to ensure consistent output quality across all generated documents. The skill definition is separate from both the user profile ([`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md)) and the command triggers (`.claude/commands/`), creating a clean separation of concerns.

## Portal Integration Layer

The **`.agents/skills/`** directory contains the search infrastructure for specific job portals.

Each subfolder (e.g., `jobindex-search/`, `linkedin-search/`, `freehire-search/`) houses a tiny TypeScript/Bun CLI tool that knows how to query a particular portal and return normalized JSON results. These tools provide the *search* layer for the `/scrape` command and follow a reusable pattern for adding new markets.

For example, the `jobindex-search` skill queries the Danish JobIndex portal, while `linkedin-search` handles LinkedIn exports. Each CLI tool operates independently, allowing the system to aggregate postings from multiple sources into a unified workflow.

## Utility and Data Infrastructure

Supporting the core workflow are several auxiliary components:

**`tools/`** – Helper scripts for salary benchmarking, skill linting, security guards, and Excel-to-JSON conversion. The [`lint_skills.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/lint_skills.py) script ensures custom skills adhere to structural requirements.

**`documents/`** – Storage for raw CVs, LinkedIn exports, diplomas, reference letters, and archived applications.

**State directories** – `job_scraper/`, `gmail_sync/`, and `upskill/` persist intermediate results (scraped jobs, processed emails, up-skill reports) so commands can be re-run idempotently without data loss.

**`job_search_tracker.csv`** – The central spreadsheet recording every application, its status, and associated metadata.

## Workflow Execution Model

The architectural components combine to implement a **self-contained, language-agnostic pipeline** that runs entirely on the user's machine:

1. **`/setup`** initializes the profile and document structure
2. **`/scrape`** invokes portal CLI tools (`.agents/skills/`) to collect and deduplicate postings
3. **`/apply`** evaluates fit against [`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md) criteria, drafts LaTeX CVs and cover letters using templates from `.claude/skills/`, and compiles PDFs
4. **`/interview`**, **`/rank`**, **`/outcome`**, and **`/upskill`** extend the loop with interview prep, ranking algorithms, outcome tracking, and learning plan generation

This pattern ensures that `.claude/` remains the *only* location for workflow logic, while external tools merely reference that specification.

## Example Command Usage

Commands are executed inside Claude Code's interactive environment:

```bash

# Initialize the system and populate CLAUDE.md

claude
> /setup

# Search configured portals for matching positions

claude
> /scrape

# Apply to a specific posting with automated document generation

claude
> /apply https://jobindex.dk/job/1234567

# Generate an offline HTML dashboard of your search progress

claude
> /html-report

```

Adding new capabilities requires only editing markdown. For example, scaffolding a new portal search tool:

```bash
claude
> /add-portal

# (Interactive prompts create a new CLI skill under .agents/skills/)

```

## Summary

- **[`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md)** serves as the single source of truth for candidate profiles and workflow rules
- **`.claude/commands/`** provides transparent, markdown-based command definitions for the Claude Code interface
- **`.claude/skills/job-application-assistant/`** contains the domain knowledge and templates for document generation
- **`.agents/skills/`** houses portal-specific TypeScript/Bun CLI tools for job scraping
- **`tools/`**, **`documents/`**, and **`job_search_tracker.csv`** provide auxiliary services and data persistence
- The **thin-pointer principle** ensures workflow logic lives only in `.claude/`, making the system maintainable and portable

## Frequently Asked Questions

### What is the thin-pointer design pattern used in ai-job-search?

The thin-pointer pattern separates declarative specifications (stored in [`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md) and `.claude/` markdown files) from executable tooling (TypeScript CLIs in `.agents/skills/`). This means the workflow logic lives entirely in text files that Claude Code reads, while heavy operations like web scraping execute in separate CLI tools. According to the repository structure, `.claude/` is the *only* place where workflow logic resides, making customization as simple as editing markdown.

### How does the system handle different job portals?

Each job portal has its own dedicated CLI tool under **`.agents/skills/`** (such as `jobindex-search/` or `linkedin-search/`). These small TypeScript/Bun applications know how to query their specific portal and return normalized JSON results. When you run `/scrape`, Claude Code invokes these tools in parallel, aggregates the results, and deduplicates them against `job_search_tracker.csv`.

### Where is my personal data stored in the ai-job-search system?

All candidate-specific data lives in **[`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md)** at the repository root and in the **`documents/`** folder. [`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md) contains your career goals, writing style preferences, and evaluation criteria, while `documents/` stores your CVs, LinkedIn exports, and reference letters. This local-first approach ensures your data never leaves your machine, as implemented in the MadsLorentzen/ai-job-search source code.

### Can I add custom LaTeX templates for CV generation?

Yes. The **`.claude/skills/job-application-assistant/`** directory contains the template definitions, and you can add new ones using the `/add-template` command. This interactive command prompts you for the template path, compile engine, and other metadata, then registers it within the skill structure. All templates are referenced by the `/apply` command when generating application materials.