# Can AI Understand Natural Language Job Descriptions? Inside the MadsLorentzen/ai-job-search Framework

> Explore the MadsLorentzen/ai-job-search framework. Discover how AI understands natural language job descriptions to parse, evaluate, and draft responses. Learn more now!

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

---

**Yes, the AI parses, evaluates, and drafts responses to free-form natural language job descriptions supplied either as URLs or raw pasted text.**

The MadsLorentzen/ai-job-search repository is an AI-driven job-application framework that treats unstructured job postings as first-class inputs. Whether you paste a description verbatim or point the tool at a URL, the pipeline extracts structured signals from raw text and uses them to evaluate fit and draft tailored application documents. The entire workflow centers on the ability to understand **natural language job descriptions** safely and accurately.

## How the `/apply` Command Processes Natural Language Job Descriptions

The core parsing and reaction logic lives in [`.claude/commands/apply.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/commands/apply.md). This file orchestrates a three-step pipeline that transforms free-form text into structured actions.

### Step 0 — Parse Input from URLs or Raw Text

The workflow first inspects the argument to determine whether it resembles a URL. If so, the system fetches the posting using `WebFetch`; otherwise, it consumes the raw text directly. According to the source code in [`.claude/commands/apply.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/commands/apply.md), the parser treats the posting as **untrusted data** and never as executable instructions. It extracts the company name, role title, department, location, and language, which become the foundation for every downstream step.

### Step 1 — Evaluate Fit Against Structured Criteria

The extracted description is compared against the candidate’s profile using the evaluation framework defined in [`.claude/skills/job-application-assistant/04-job-evaluation.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/skills/job-application-assistant/04-job-evaluation.md). This step scores skills, experience, cultural fit, and optional salary benchmarks. The AI maps ambiguous natural-language requirements to concrete structured signals, demonstrating genuine comprehension of the post’s intent.

### Step 2 — Draft CV and Cover Letter

The same parsed information feeds the drafting stage in Step 2. The AI ensures that every requirement from the posting is either addressed in the generated documents or honestly acknowledged as a gap. This closes the loop by turning raw text into tailored application materials.

## Job Scraper Tools That Feed Natural Language Data

The repository includes CLI agents in `.agents/skills/`—such as `jobindex-search` and `linkedin-search`—that retrieve listings from various portals. These tools are thin wrappers around HTTP requests and HTML parsing. They return the raw posting text that the AI subsequently consumes, pumping external natural language job descriptions into the same `/apply` pipeline.

## Security: Treating Postings as Untrusted Data

Because the workflow explicitly treats every posting as untrusted data, it safely ingests arbitrary natural language job descriptions while preserving security guarantees. The parser never executes embedded instructions, so even maliciously crafted text cannot hijack the agent.

## Practical Code Examples

### Apply to a Posting via URL

Invoke the full pipeline by passing a job URL directly to the Claude CLI:

```bash
claude /apply https://jobindex.dk/job/1234567

```

The command fetches the page, parses the natural language job description, evaluates fit, drafts the documents, and returns the final PDFs.

### Apply by Pasting the Description

When no URL is provided, the command falls back to raw text input:

```bash
claude /apply

```

Paste the full job description when prompted. The `/apply` command uses the same parsing logic for pasted text as it does for fetched HTML.

### Run a Scraper Manually

You can retrieve listings locally using the Bun-based LinkedIn scraper:

```bash
cd .agents/skills/linkedin-search/cli
bun run src/main.ts --query "machine learning engineer" --location "Berlin, Germany"

```

The scraper prints JSON-encoded job postings that can be piped into `/apply` or inspected manually.

### Programmatic Evaluation with Salary Lookup

During Step 1, the framework can enrich the fit report with salary data by invoking [`salary_lookup.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/salary_lookup.py):

```python
import subprocess, json

result = subprocess.check_output(
    ['python', 'salary_lookup.py', 'Danske Bank', '--json', '--city', 'Copenhagen']
)
salary_info = json.loads(result)
print(salary_info)

```

The JSON result is merged into the fit report generated by the evaluation step in [`.claude/commands/apply.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/commands/apply.md).

## Key Files in the Natural Language Pipeline

Several files define how the system interprets natural language job descriptions:

- [`.claude/commands/apply.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/commands/apply.md) — Orchestrates the full drafter-reviewer pipeline and parses natural-language postings in Step 0.
- [`.claude/skills/job-application-assistant/04-job-evaluation.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/skills/job-application-assistant/04-job-evaluation.md) — Defines the structured evaluation framework that maps description text to fit scores.
- [`.agents/skills/linkedin-search/cli/src/main.ts`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.agents/skills/linkedin-search/cli/src/main.ts) — Example CLI scraper that supplies raw job-description text to the AI.
- [`salary_lookup.py`](https://github.com/MadsLorentzen/ai-job-search/blob/main/salary_lookup.py) — Utility invoked during fit evaluation to enrich the AI’s understanding with salary benchmarks.
- [`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md) — Holds the candidate profile that the AI matches against parsed job descriptions.

## Summary

- The `/apply` command in [`.claude/commands/apply.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/commands/apply.md) accepts **natural language job descriptions** via URL or raw text and extracts structured fields such as company, role, and location.
- Step 1 evaluates fit by mapping parsed requirements against the candidate profile in [`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md) using the framework in [`04-job-evaluation.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/04-job-evaluation.md).
- Step 2 generates tailored CV and cover letter content, addressing each requirement or noting gaps honestly.
- Scraper tools in `.agents/skills/` feed external job board text into the same pipeline.
- The system treats all input as untrusted data, preventing instruction injection while fully processing free-form descriptions.

## Frequently Asked Questions

### Can the AI process job descriptions pasted as plain text instead of URLs?

Yes. The `/apply` command falls back to raw text parsing when no URL is provided. It uses the same extraction logic to identify company name, role title, department, location, and language before proceeding to evaluation and drafting.

### How does the AI evaluate whether a candidate fits a natural language job description?

Step 1 of the `/apply` workflow compares the parsed description against the candidate profile stored in [`CLAUDE.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/CLAUDE.md). It uses the framework defined in [`.claude/skills/job-application-assistant/04-job-evaluation.md`](https://github.com/MadsLorentzen/ai-job-search/blob/main/.claude/skills/job-application-assistant/04-job-evaluation.md) to generate structured scores for skills, experience, cultural fit, and optional salary benchmarks.

### Are job postings treated as safe input?

Yes, by design. The workflow explicitly treats every posting as untrusted data. It parses the text for information but never executes embedded instructions, enabling safe ingestion of arbitrary natural language job descriptions.

### What tools fetch job listings for the AI to process?

The CLI agents in `.agents/skills/`—including `jobindex-search` and `linkedin-search`—retrieve raw posting text from various portals. These thin HTTP wrappers feed natural language job descriptions into the same `/apply` pipeline.