AI Job Search Framework Architecture: A Deep Dive into the Thin-Pointer Design
The AI Job Search framework uses a thin-pointer architecture built around four layers—a canonical candidate profile, markdown-driven workflow specifications, modular portal-specific skills, and reusable core utilities.
This open-source automation system, maintained at MadsLorentzen/ai-job-search, eliminates configuration drift by making a single source of truth the driver for all agents, commands, and data. Every component reads from centralized specifications rather than maintaining independent state.
Four Core Architectural Layers
1. Candidate Profile (Canonical Data) — CLAUDE.md and Skill Files
The foundation of the framework is 集中式数据存储. All agent runtimes load candidate information from one location.
CLAUDE.md— Master file containing personal details, education, preferences, and CV information.claude/skills/job-application-assistant/— Directory of skill-specific supplements (e.g.,01-*.mdfiles)
This design prevents duplication. When a candidate updates their profile in CLAUDE.md, every downstream agent automatically uses the refreshed data.
2. Workflow Specification (Orchestration) — .claude/commands/
High-level processes are defined as pure markdown specifications rather than hardcoded logic.
| Command File | Purpose |
|---|---|
.claude/commands/setup.md |
Environment initialization |
.claude/commands/rank.md |
Job ranking workflow |
.claude/commands/apply.md |
Application submission |
.claude/commands/scrape.md |
Data collection |
.claude/commands/upskill.md |
Interview preparation |
A generic runner interprets these markdown files and stitches together the required tools. Non-programmers can edit workflows without touching source code.
3. Portal-Specific Skills (Plug-ins) — .agents/skills/
Each job portal operates as a self-contained skill module:
.agents/skills/
├── linkedin-search/
│ ├── SKILL.md # Markdown description
│ └── cli/ # TypeScript implementation
├── jobnet-search/
├── freehire-search/
└── [new-portal]/ # Auto-discovered on commit
The LinkedIn skill demonstrates the pattern:
.agents/skills/linkedin-search/SKILL.md— Defines required CLI flags (--query,--location), output format (JSON), and rate-limit handling.agents/skills/linkedin-search/cli/— Houses the TypeScript entry point and package configuration
The core runner automatically discovers new skill folders. Adding a portal requires zero changes to the orchestration layer.
4. Core Utilities and Test Suite — tools/ and tests/
Reusable components accessible across all commands:
| Tool | Function |
|---|---|
tools/verify_pdf.py |
LaTeX source validation for cover letters |
tools/salary_lookup.py |
Region-adjusted compensation data |
tools/rank.py |
Ranking algorithm implementation |
The tests/ directory contains 30+ unit and integration test files. Example: tests/test_rank_command.py validates the ranking workflow end-to-end.
Key Architectural Principles
- Single Source of Truth — All specifications live in
.claude/; all candidate data inCLAUDE.md. This eliminates drift between agent instances. - Modular Skill Plugins — Portal logic is encapsulated, making replacement trivial.
- Command-Driven Workflow — Markdown specifications allow declarative process definition.
- Extensive Test Coverage — Every skill, tool, and command has automated validation.
- Tool-Centric Utilities — DRY patterns encourage reuse across commands.
Code Examples
Adding a New Portal Skill
Create the folder structure:
mkdir -p .agents/skills/myportal-search/cli
Add SKILL.md:
# MyPortal Search Skill
This skill scrapes job listings from MyPortal.
- Required flags: `--query`, `--location`
- Output: JSON array of listings
- Rate limit: 1 request/second
The runner detects the new skill on next execution.
Running the Rank Command
python -m ai_job_search rank \
--profile CLAUDE.md \
--input ./job_scraper/results.json \
--output ./ranked_jobs.json
The rank command loads the candidate profile from CLAUDE.md, applies the algorithm in tools/rank.py, and outputs the ordered list.
Verifying a PDF Resume
from tools.verify_pdf import verify_pdf
result = verify_pdf("cover_letters/cover_example.tex")
print(result)
# → {"valid": true, "issues": []}
The verify_pdf function parses LaTeX source, checks for required sections, and returns a JSON-compatible report.
Looking Up Salary Data
from salary_lookup import lookup_salary
salary = lookup_salary(company="Acme Corp", title="Software Engineer")
print(f"Estimated salary: ${salary:,.0f}")
salary_lookup.py queries cached CSV data and applies regional multipliers.
Critical Source Files
| Path | Role |
|---|---|
CLAUDE.md |
Central candidate profile |
.claude/commands/setup.md |
Setup command specification |
.claude/commands/rank.md |
Ranking workflow definition |
.agents/skills/linkedin-search/SKILL.md |
LinkedIn skill description |
tools/verify_pdf.py |
PDF verification utility |
salary_lookup.py |
Salary lookup helper |
tests/test_rank_command.py |
Rank command unit tests |
SETUP.md |
Detailed installation guide |
Summary
- The thin-pointer architecture centralizes all state in
CLAUDE.mdand.claude/specifications - Markdown-driven commands enable non-programmer workflow customization
- Self-contained skill modules allow portal addition without core changes
- Shared utilities in
tools/enforce DRY principles - Comprehensive test coverage in
tests/ensures reliability as the framework scales
Frequently Asked Questions
How does the framework handle new job portals?
Drop a new folder under .agents/skills/ with a SKILL.md description and CLI implementation. The generic runner auto-discovers the skill on next execution—no orchestration code changes required.
Where is candidate data stored?
All candidate information lives in CLAUDE.md at the repository root, supplemented by skill files in .claude/skills/job-application-assistant/. This single source of truth prevents synchronization errors across agents.
Can non-developers modify workflows?
Yes. Workflow steps are defined in markdown files under .claude/commands/. Users can edit rank.md, apply.md, or other command specifications without writing code—the runner interprets the markdown directly.
What testing coverage exists?
The tests/ directory contains over 30 files covering unit and integration scenarios. Every command, skill, and core utility has corresponding test files like tests/test_rank_command.py.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →