Agents · REPO · 2026
MadsLorentzen/ai-job-search
요약
MadsLorentzen/ai-job-search는 Claude Code를 구직 지원 도구로 바꾸는 MIT 라이선스 프레임워크다. 저장소를 fork해 자신의 프로필을 채우면, 세 개의 커맨드가 공고 수집부터 맞춤 CV와 커버레터 작성까지 한 줄기로 처리한다.
이 저장소를 다른 Claude Code 커맨드 팩과 구분 짓는 지점은 산출물 검증이다. 대다수 이력서 생성 도구는 텍스트를 만들어 놓고 끝난다. 이 프레임워크는 LaTeX 소스를 실제로 컴파일하고, 렌더링된 PDF를 눈으로 확인하고, PDF에 내장된 텍스트 레이어를 추출해 채용 시스템이 읽을 결과까지 검사한 다음에야 사용자에게 결과를 넘긴다.
저자 Mads Lorentzen은 지구물리학 전공자다. 2025년 말 자신의 자리가 없어지자 이 프레임워크를 만들어 자신의 구직에 매주 사용했고, 맞춤 지원 69건과 1차 면접 20건을 거쳐 2026년 6월 AI 엔지니어로 입사했다. README는 이 결과를 벤치마크 대신 내세운다.
배경
구직 지원서 자동 생성은 두 가지 실패 지점을 함께 안고 있다. 하나는 내용의 실패이고, 다른 하나는 형식의 실패다.
내용의 실패는 지원서가 일반적인 문장으로 채워지는 것이다. 모델 하나가 초안을 쓰고 스스로 검토하면 키워드 누락과 약한 프레이밍이 그대로 남는다. 또 다른 방향의 실패는 반대편에 있다. ATS 통과율을 올리려고 프로필이 뒷받침하지 않는 키워드를 채워 넣으면 지원서가 사실과 어긋난다.
형식의 실패는 더 조용히 일어난다. LaTeX 이력서 템플릿은 .tex 단계에서 문제가 없어 보여도 PDF에서 깨진다. 직함이 페이지 끝에 고아로 남거나, 커버레터가 2페이지로 밀리거나, 불릿의 폰트가 본문 폰트로 조용히 대체된다. 여기에 더해 LaTeX는 텍스트가 깨져 추출되는 PDF를 만들어낼 수 있다. 이메일 자리에 아이콘 글리프가 들어가거나 다단 레이아웃에서 줄이 뒤섞이면, 사람 눈에는 온전한 CV가 채용 시스템에서는 읽히지 않는다.
이 저장소는 두 실패에 각각 다른 장치를 배치한다. 내용에는 drafter-reviewer 2단계 구조와 honesty rule을, 형식에는 PDF 컴파일 검사 루프와 텍스트 레이어 검증을 둔다.
여기에 더해 커리어 가이던스의 통념을 워크플로 안에 코드로 고정한다. 구조화된 평가 기준, 과거 성과가 아니라 앞으로 할 일을 중심에 두는 커버레터 프레이밍, 선택적 연봉 벤치마킹이 그 내용이다. 매번 사람이 기억해서 적용할 규칙을 커맨드 정의와 스킬 파일에 옮겨 둔 셈이다.
핵심 개념
ATS(Applicant Tracking System) 는 채용 담당자가 이력서를 자동으로 파싱하고 필터링하는 시스템이다. 이 시스템은 PDF의 렌더링된 페이지가 아니라 PDF 안에 내장된 텍스트 레이어를 읽는다. 그래서 화면에 보이는 모습과 파서가 받아 가는 텍스트가 갈라질 수 있으며, 이 프레임워크의 검증 단계는 후자를 기준으로 삼는다.
drafter-reviewer workflow는 초안을 쓰는 에이전트와 비평만 담당하는 에이전트를 분리한 2단계 구조다. 리뷰어는 새 컨텍스트로 스폰되므로 초안 작성 과정의 맥락에 물들지 않은 상태에서 결과물만 본다. 한 에이전트가 쓰고 검토까지 하는 단일 패스보다 키워드 누락과 일반적인 표현을 잘 잡는다.
fit evaluation은 공고와 프로필의 적합도를 다섯 항목으로 점수화하는 프레임워크다. 스킬, 경력, 조직문화, 위치, 커리어 정합성을 본다. /rank와 /apply가 같은 프레임워크를 공유하기 때문에, 선별 단계에서 매긴 점수와 지원 단계에서 다시 매긴 점수가 같은 기준 위에 놓인다.
honesty rule은 프로필이 실제로 뒷받침하는 키워드만 CV에 넣고 뒷받침되지 않는 키워드는 격차로 남겨 두는 원칙이다. ATS 키워드 매칭과 사실성 사이의 교환을 사실성 쪽으로 고정한다. README는 CV와 커버레터의 모든 주장을 실제 프로필과 대조해 검증하며 시스템이 스킬이나 경력을 지어내지 않는다고 명시한다.
relevance-weighted cutting은 CV가 페이지 상한을 넘길 때 적용하는 삭제 규칙이다. 가장 오래된 절부터 기계적으로 자르는 대신 각 줄에 점수를 매겨 총점이 가장 낮은 줄부터 제거한다.
system of record는 어떤 데이터의 정본이 어디에 있는지를 지정하는 개념이다. 이 프레임워크에서는 저장소 파일이 정본이고, Notion으로 발행되는 뷰는 읽기 전용 사본이다.
방법
전체 흐름
세 개의 코어 커맨드가 한 줄기를 이룬다. /setup이 프로필을 만들고, /scrape가 공고를 모으고, /apply가 지원서를 생성한다. 나머지 커맨드는 이 줄기에 붙는 확장이다.
| 구분 | 커맨드 | 개수 | 역할 |
|---|---|---|---|
| 코어 워크플로 | /setup, /scrape, /apply |
3 | 프로필 구축, 공고 수집, 지원서 생성 |
| 확장 | /interview, /outcome, /notion-sync, /rank, /expand, /upskill, /html-report, /add-template, /add-portal |
9 | 선별, 면접 준비, 결과 기록, 가시화, 커스터마이징 |
| 초기화 | /reset |
1 | 프로필 데이터 삭제 |
README가 그린 파이프라인은 각 단계의 입력과 출력을 한 줄로 이어 놓는다.
| 단계 | 사용자가 하는 일 | 시스템이 내놓는 것 |
|---|---|---|
/setup |
프로필을 채운다 | 프로필 파일 일습이 준비된다 |
/scrape |
구직 포털을 검색한다 | fit 등급이 붙은 공고 목록을 제시한다 |
/apply <url> |
목록에서 공고를 고른다 | fit을 평가해 점수와 권고를 내고, 맞춤 LaTeX CV와 커버레터 초안을 쓰고, 리뷰어 에이전트의 비평을 반영해 수정한 최종 산출물을 낸다 |
실행에 필요한 환경은 다음과 같다.
| 항목 | 조건 | 비고 |
|---|---|---|
| Claude Code | CLI 필요 | Codex, Antigravity, Gemini CLI 사용자는 AGENTS.md에서 시작한다. 포털 검색 스킬은 그대로 동작하고, 전체 워크플로 이식은 커뮤니티 fork가 다룬다 |
| Python | 3.10 이상 | |
| Bun | 필요 | 구직 검색 CLI 도구 실행용 |
| LaTeX 배포판 | lualatex와 xelatex 포함 |
TeX Live, MacTeX, TinyTeX, MiKTeX 중 선택 |
pdftotext (poppler) |
선택 | ATS 파싱 검사에 쓴다. 없으면 시각적 키워드 검토로 degrade하고 워크플로는 계속 진행된다 |
CV와 커버레터가 서로 다른 엔진을 쓰는 데는 각각 이유가 있다. CV를 lualatex로 컴파일하는 것은 최신 MiKTeX에서 pdflatex가 fontawesome5 폰트 확장 오류로 실패하는 경우가 잦기 때문이다. 커버레터가 xelatex를 쓰는 것은 커스텀 클래스 cover.cls가 fontspec을 요구하기 때문이다. TinyTeX나 BasicTeX 같은 미니멀 배포판을 쓰면 SETUP.md가 안내하는 추가 패키지를 따로 설치해야 한다.
로컬 실행 전제
README의 태그라인은 "The job search that runs on your machine."이다. 이 문장은 문구 이상의 설계 제약을 담는다.
프로필, 지원 이력, 스크래퍼 상태, 추적 스프레드시트가 모두 사용자 fork 안의 파일로 존재한다. 서비스 계정도 없고 중앙 데이터베이스도 없으며, 이력서 초안과 커리어 이력이 외부 서버로 올라가지 않는다.
이 전제는 산출물 설계에도 그대로 나타난다. /html-report가 만드는 대시보드는 차트를 인라인 SVG로 그려 외부 의존성이 없고 완전히 오프라인으로 열린다. 구직 포털 CLI 도구는 로컬에서 실행되며, linkedin-search와 freehire-search는 런타임 의존성조차 없다. 바깥으로 나가는 유일한 통합은 /notion-sync이고, 그마저 단방향 읽기 전용이라 저장소가 정본 자리를 유지한다.
설치와 첫 실행
사용은 fork에서 시작한다. 이 프레임워크는 프로필과 지원 이력을 저장소 안에 파일로 두기 때문에, 사용자마다 자기 fork를 갖는 것이 전제다.
gh repo fork MadsLorentzen/ai-job-search --clone
cd ai-job-search
다음으로 구직 검색 CLI 도구를 설치한다. 여섯 개 스킬 각각의 cli/ 디렉토리에서 bun install을 실행한다.
for tool in jobbank-search jobdanmark-search jobindex-search jobnet-search linkedin-search freehire-search; do
(cd .agents/skills/$tool/cli && bun install)
done
이후 claude로 Claude Code를 띄우고 /setup으로 프로필을 채운 뒤 /scrape로 공고를 모으고, 고른 공고의 URL을 /apply에 넘긴다. 이때 URL 대신 공고 본문을 그대로 붙여넣어도 된다.
프로필 구축
/setup은 온보딩 경로 세 가지를 자동 감지해 사용자에게 제시한다.
| 경로 | 입력 | 특징 |
|---|---|---|
| documents 폴더 | documents/ 하위의 CV PDF, LinkedIn export, 졸업장, 추천서, 과거 지원 기록 |
idempotent라서 자료를 추가하며 재실행해도 안전하다. 폴더 구조는 documents/README.md가 안내한다 |
| CV 붙여넣기 | 채팅에 붙여넣은 CV 한 장 | 단일 문서로 프로필을 구성한다 |
| 인터뷰 | 대화형 질문 응답 | 문서 없이 처음부터 채운다 |
프로필을 한 번 채운 뒤 검색 설정만 다시 잡고 싶으면 전체 온보딩을 반복할 필요가 없다. /setup --section search가 검색 설정 인터뷰만 실행한다. 목표 직무, 검색할 스킬, 지역, 사용할 포털을 다시 정하며, 프로필로 미루어 사용자가 고려하지 않았을 법한 직무 유형도 함께 제안한다.
커맨드를 쓰지 않고 파일을 직접 편집하려는 사용자를 위해 README는 파일별 편집 대상을 표로 제공한다.
| 파일 | 편집할 내용 |
|---|---|
CLAUDE.md |
전체 프로필 (이름, 학력, 경력, 스킬, 목표) |
01-candidate-profile.md |
CV 데이터의 구조화 버전 |
02-behavioral-profile.md |
성향 평가 또는 자가 평가 |
04-job-evaluation.md |
스킬 매칭 영역, 커리어 목표, 동기 필터 |
05-cv-templates.md |
직무 유형별 프로필 서술 템플릿 |
07-interview-prep.md |
실제 경험에서 뽑은 STAR 예시 |
search-queries.md |
보유 스킬과 지역에 맞춘 구직 검색 질의(query) |
공고 수집과 선별
/scrape는 여러 구직 포털을 검색해 프로필에 맞는 공고를 찾고, 중복을 제거한 뒤 fit 순으로 정렬해 보여준다. 여기서 마음에 드는 공고를 골라 바로 /apply로 넘어갈 수 있다.
결과가 눈으로 훑기 어려울 만큼 많으면 /rank가 사이에 들어간다. 병렬 에이전트가 각 공고를 가져와 fit 프레임워크의 다섯 평가 항목을 채점하고, 공고별 강점과 격차를 솔직하게 붙인 순위 shortlist를 낸다. 세 가지 표시 규칙이 함께 적용된다.
| 규칙 | 동작 |
|---|---|
| deal-breaker | 필수 조건에 걸리는 공고는 거부권으로 제외한다 |
| 마감 임박 | 긴급 표시를 붙인다 |
| 마감 완료 | 만료 표시를 붙인다 |
순위 목록에서 번호를 고르면 그대로 /apply 워크플로로 넘어간다.
/apply는 공고 URL을 인자로 받는다. 자동 접근을 차단하는 포털이라 URL을 가져올 수 없는 경우에는 공고 본문 전체를 그대로 붙여넣는 방식도 지원한다.
지원서 생성 8단계
/apply는 여덟 단계를 순서대로 실행한다.
| 단계 | 내용 |
|---|---|
| 1 | 공고 파싱 (URL 또는 붙여넣은 텍스트) |
| 2 | 프로필 대비 fit 평가 (스킬, 경력, 조직문화, 위치, 커리어 정합성 다섯 항목) |
| 3 | LaTeX로 맞춤 CV와 커버레터 초안 작성 |
| 4 | 리뷰어 에이전트 스폰. 회사를 리서치하고 초안을 비평한다 |
| 5 | 리뷰어 피드백을 반영해 수정 |
| 6 | 두 PDF 컴파일과 시각 검사 (CV는 lualatex, 커버레터는 xelatex) |
| 7 | CV의 ATS 검사. 텍스트 레이어를 추출해 파싱 결과를 검증하고 키워드 커버리지를 점수화 |
| 8 | 검증 체크리스트와 함께 최종 산출물 제시 |
앞의 세 단계가 내용을 만들고, 뒤의 세 단계가 그 내용을 검증한다. 2단계의 fit 평가는 점수만 내는 것이 아니라 지원 여부에 대한 권고까지 함께 제시한다. 3단계는 프로필을 그대로 옮기는 것이 아니라 대상 공고에 맞춰 재구성한다.
4단계에서 스폰되는 리뷰어는 초안을 쓴 에이전트와 다른 Claude 에이전트다. 새 컨텍스트로 시작하기 때문에 초안이 어떤 의도로 쓰였는지 모르는 상태에서 결과물만 평가한다. 이 분리가 단일 패스에서 흔히 남는 세 가지, 곧 누락된 키워드와 약한 프레이밍과 일반적인 표현을 잡아낸다.
두 에이전트의 역할은 다음과 같이 나뉜다.
| 역할 | 컨텍스트 | 하는 일 |
|---|---|---|
| drafter | 프로필과 공고를 모두 들고 있다 | CV와 커버레터 초안을 쓰고, 리뷰어 피드백을 받아 수정한다 |
| reviewer | 새로 스폰된 빈 컨텍스트에서 초안만 인라인으로 받는다 | 회사를 리서치하고 초안을 비평한다 |
PDF 컴파일과 시각 검사
6단계는 이 프레임워크가 다른 이력서 생성 도구와 갈라지는 지점이다. 초안 작성으로 끝내지 않고 실제로 컴파일한 PDF를 Claude가 읽는다.
검사 기준은 문서 종류마다 다르다.
| 문서 | 컴파일 엔진 | 통과 조건 |
|---|---|---|
| CV | lualatex | 정확히 2페이지이고, 직함이 페이지 끝에 고아로 남지 않는다 |
| 커버레터 | xelatex | 정확히 1페이지이고, 서명이 보이며, 폰트가 일관된다 |
조건을 만족하지 못하면 LaTeX 소스를 수정하고 다시 컴파일한다. 적용하는 수정은 임의의 재작성이 아니라 표적화된 조판 명령이다. \needspace로 블록이 쪼개지지 않을 최소 공간을 확보하고, \enlargethispage로 특정 페이지의 높이를 조정하며, 리스트 항목에는 폰트 매칭 wrapper를 씌운다. 이 루프는 모든 지원 건에서 자동으로 실행된다.
ATS 텍스트 레이어 검증
7단계는 컴파일된 CV를 채용 시스템의 관점에서 다시 읽는다. pdftotext로 PDF의 텍스트 레이어를 추출한 뒤 세 가지를 확인하고, 그 위에서 키워드 커버리지를 점수화한다.
| 검사 항목 | 확인 내용 | 실패하면 생기는 문제 |
|---|---|---|
| 연락처 | 이메일과 전화번호가 리터럴 텍스트로 존재하는가 | 아이콘 글리프로 렌더링되면 파서가 연락처를 못 읽는다 |
| 글리프 | 추출된 문자가 깨지지 않았는가 | 폰트 매핑이 어긋나면 텍스트가 알아볼 수 없는 문자열이 된다 |
| 읽기 순서 | 줄 순서가 온전한가 | 다단 레이아웃에서 좌우 열의 줄이 뒤섞여 문장이 붙는다 |
세 항목을 나눠 검사하는 이유는 실패 양상이 서로 다르기 때문이다. 연락처 문제는 지원자에게 연락할 수 없게 만들고, 글리프 문제는 문서 전체를 무의미한 문자열로 만들며, 읽기 순서 문제는 내용은 남되 문장의 의미를 흐트러뜨린다. 세 경우 모두 사람이 화면으로 확인해서는 발견되지 않는다.
키워드 점수는 렌더링된 화면이 아니라 이 추출 결과를 기준으로 매긴다. 여기에 honesty rule이 걸린다. 프로필이 실제로 뒷받침하는 키워드는 CV에 추가하고, 뒷받침되지 않는 키워드는 채워 넣지 않고 격차로 드러낸 채 남긴다.
연관성 가중 CV 컷팅
CV가 2페이지를 넘기면 무엇을 지울지 정해야 한다. 이 프레임워크는 가장 오래된 절부터 자르는 기계적 규칙을 쓰지 않는다. 후보가 되는 줄마다 세 가지를 점수화하고 총점이 가장 낮은 줄부터 제거한다.
| 점수 항목 | 묻는 것 |
|---|---|
| 연관성 | 이 줄이 대상 공고와 얼마나 관련되는가 |
| 고유성 | 이 내용이 문서 안에서 얼마나 유일한가 |
| 의존도 | 커버레터가 이 줄에 기대고 있는가 |
세 항목은 서로 다른 종류의 손실을 막는다. 연관성은 공고와 무관한 내용이 지면을 차지하는 것을, 고유성은 같은 말이 두 번 들어가 한 번은 낭비되는 것을, 의존도는 커버레터가 언급한 근거가 CV에서 사라져 두 문서가 어긋나는 것을 막는다.
이 규칙의 효과는 순서 역전으로 나타난다. 공고 키워드에 맞는 오래된 경력의 불릿이, 키워드에 맞지 않는 최근 경력의 불릿보다 먼저 살아남는다.
토큰 예산 설계
에이전트를 두 개 쓰면 토큰이 두 배로 드는 것이 자연스러운 예상이다. 이 저장소는 두 가지 방식으로 그 비용을 낮춘다.
첫째, 리뷰어 에이전트는 초안을 파일에서 다시 읽지 않고 인라인으로 전달받는다. 둘째, 검증 체크리스트를 두 에이전트가 각각 실행하지 않고 워크플로 끝에서 한 번만 실행한다.
이 두 가지가 겨냥하는 것은 서브에이전트 구조의 대표적 낭비다. 초안을 파일에서 다시 읽으면 같은 텍스트가 두 컨텍스트에 중복으로 들어가고, 체크리스트를 양쪽이 각자 실행하면 같은 검사가 두 번 청구된다.
다만 README는 이 절감이 온전히 남지 않는다고 밝힌다. 새로 추가된 컴파일과 검사 단계가 절감분의 일부를 PDF 렌더링과 레이아웃 반복에 다시 쓴다. 저자는 이를 교환으로 설명한다. 종단 간 토큰 비용의 일부를 지불하는 대신, 깨진 PDF가 사용자에게 도달하는 일을 실제로 줄인다.
구직 포털 스킬
.agents/skills/ 아래에 CLI 스킬 여섯 종이 들어 있다. 설치는 각 스킬의 cli/ 디렉토리에서 bun install을 실행한다.
| 스킬 | 대상 | 성격 |
|---|---|---|
jobbank-search |
Akademikernes Jobbank (덴마크) | HTML 스크래핑 방식 데모 |
jobdanmark-search |
Jobdanmark.dk (덴마크) | 동일 |
jobindex-search |
Jobindex.dk (덴마크) | 동일 |
jobnet-search |
Jobnet.dk (덴마크 정부 포털) | 동일 |
linkedin-search |
LinkedIn 공개 jobs-guest 엔드포인트 |
국가 무관, 분야 무관, 런타임 의존성 0 |
freehire-search |
freehire.dev 집계 서비스의 공개 REST API | 기술 직군 중심, 다중 시장, 런타임 의존성 0 |
덴마크 포털 네 종은 특정 시장을 위한 통합을 어떻게 만드는지 보여주는 예시에 해당한다. 나머지 두 종이 다른 나라 사용자의 출발점이다.
linkedin-search는 검색 위치를 명시적 플래그로 받는다. -l "Berlin, Germany"나 -l "Remote"처럼 지정하면 어느 시장에서도 바로 동작한다. 다만 자동화 접근이 LinkedIn 이용약관에 어긋나므로 개인 사용 전용이며 저볼륨 사용을 전제로 제공한다.
freehire-search는 소프트웨어, 데이터, 엔지니어링, DevOps, 원격 직군을 다루며 --region, --country, --remote 패싯 플래그로 시장을 좁힌다. HTML을 수집하는 덴마크 포털과 달리 결과가 스킬, 연차, 카테고리로 구조화되어 돌아온다. 백엔드가 MIT 라이선스라 자체 호스팅이 가능하고, FREEHIRE_API_URL을 자기 인스턴스로 지정할 수 있다. 이 두 스킬은 런타임 의존성이 없어 bun install이 선택 사항이며, 설치하더라도 TypeScript 개발용 타입만 가져온다.
구직 검색 CLI 스킬의 출처는 README의 감사 표기가 밝힌다. Mikkel Krogholm과 그의 skills 저장소를 CLI 스킬의 출처로 명시한다.
자기 나라 포털을 추가하려면 /add-portal을 쓴다. 포털의 검색 URL 패턴, 결과 페이지 구조, robots.txt와 접근 규칙을 먼저 조사하고, 기존 스킬과 같은 구조와 커맨드와 출력 계약으로 CLI 스킬을 스캐폴딩한 뒤, 실제 질의를 한 번 실행해 확인하고 등록한다. 인증 장벽이 있는 포털은 생성을 거절하고, 제약이 강한 약관의 포털은 생성된 스킬 안에 개인 사용 전용 경고를 눈에 띄게 넣는다. 생성된 스킬은 사용자의 fork에만 존재하는 시장 전용 자산이고, 재사용되는 보편적 부분은 생성기 쪽이다.
지원 이후의 되먹임
지원서를 보내고 나면 세 개의 커맨드가 이어진다.
| 커맨드 | 하는 일 | 세부 |
|---|---|---|
/interview |
예정된 면접을 준비한다 | 지원 아카이브에서 실제 공고 원문, 면접관이 읽은 CV와 커버레터, 이전 라운드에서 기록한 피드백을 꺼내 단계별 준비팩을 만든다. 회사와 면접관은 verify-before-use 규칙으로 리서치하고, 예상 질문을 STAR 예시에 매핑하며, 07-interview-prep.md의 롤플레이 프로토콜로 모의 면접을 제안한다. 격차에는 솔직한 bridge 답변을 주고 경험을 지어내지 않는다 |
/outcome |
결과를 기록한다 | 면접 단계, 오퍼, 불합격, 무응답을 남긴다. 제출한 CV와 커버레터와 공고 텍스트를 documents/applications/<company>_<role>/에 아카이브하고, /setup Path A가 파싱하는 형식으로 outcome.md를 유지하며 tracker를 갱신한다 |
/expand |
프로필을 보강한다 | 프로필에 이미 링크된 공개 소스(GitHub 저장소, 포트폴리오 사이트, Kaggle, Google Scholar)를 스캔하고 명시된 강의와 자격증의 syllabus를 조회한다. 발견된 역량은 출처 태그를 달아 프로필에 추가한다 |
/interview가 준비팩을 만들 때 쓰는 재료는 일반적인 면접 자료가 아니라 그 지원 건의 실제 이력이다. 면접관이 읽은 CV와 커버레터를 그대로 꺼내 쓰기 때문에, 준비팩의 예상 질문이 실제로 제출된 문서에 근거한다. 회사와 면접관 정보에는 verify-before-use 규칙이 걸려 확인되지 않은 내용은 준비팩에 들어가지 않는다. 프로필에 없는 역량을 묻는 질문에는 경험을 지어내는 대신 격차를 인정하고 인접 경험으로 잇는 bridge 답변을 준다.
/outcome은 단순 기록으로 끝나지 않고 루프를 닫는다. 지원 건 몇 개가 결론이 나면 실제로 면접까지 간 사례를 기준으로 fit 프레임워크를 보정하도록 사용자를 /setup으로 되돌려 보낸다. /outcome이 저장하는 아카이브는 /interview의 준비팩 재료이자 /setup의 보정 입력이 되므로, 세 커맨드가 하나의 순환을 이룬다.
파이프라인 가시화
수집한 공고와 진행 중인 지원 건을 보는 방법이 두 가지 있다. 둘은 대체 관계가 아니라 보완 관계다.
| 커맨드 | 산출물 | 특성 |
|---|---|---|
/html-report |
self-contained HTML 대시보드 | job_search_tracker.csv와 지원 아카이브에서 생성한다. 통계 카드와 상태, 섹터, 채널, funnel 차트를 인라인 SVG로 그려 외부 의존성이 없고, 필터 가능한 지원 테이블을 포함한다. 브라우저에서 바로 열리며 완전히 오프라인으로 동작한다 |
/notion-sync |
Notion 데이터베이스의 읽기 전용 뷰 | 공식 Notion MCP 서버(OAuth, API 키 불필요)로 발행한다. 순위가 매겨진 공고 한 건당 한 행과 추적 중인 모든 지원 건을 쓰고, 행마다 write-once 브리핑 페이지를 붙인다 |
/html-report가 책상에서 재생성하는 심층 대시보드라면, /notion-sync는 Notion이 실행되는 모든 기기에서 볼 수 있는 요약 뷰다. /notion-sync의 동기화는 단방향이다. 저장소 파일이 system of record로 남아 역방향 동기화가 없고, 문서는 파일명만 동기화한다.
/upskill은 가시화와 계획 사이에 있다. 프로필과 추적 중인 공고 사이의 격차를 분석해 우선순위가 매겨진 격차 히트맵을 만들고, 웹에서 검색한 학습 자료와 소요 시간 추정을 담은 학습 계획을 붙인다. /upskill <URL>로 단일 공고만 대상으로 삼을 수도 있다.
템플릿 교체와 초기화
/add-template은 사용자 자신의 LaTeX 템플릿을 기본 템플릿 대신 등록한다. .tex 파일과 함께 .cls, .sty, 번들 폰트를 받고, 인터뷰로 컴파일 엔진과 폰트 위치와 지켜야 할 스타일 규칙과 페이지 상한을 확보한다. 확보한 정보를 templates/ 아래에 저장한 뒤 필수 테스트 컴파일을 실행하고, 통과하면 /apply가 그 템플릿으로 초안을 쓰도록 연결한다.
템플릿은 개인 정보 대신 [PLACEHOLDER] 토큰으로 저장한다. 그래서 등록한 템플릿을 commit하고 공유해도 안전하다. --list로 등록된 템플릿을 확인하고, --use <name>으로 전환하며, --use default로 기본 템플릿(moderncv banking 스타일과 cover.cls)으로 되돌린다.
/reset은 프로필 데이터를 지운다. /reset profile은 스킬 파일을 지우되 프레임워크 규칙은 보존하고, /reset documents는 documents/ 폴더의 파일을 삭제하며, /reset all은 둘 다 수행한다. 삭제 대상을 먼저 보여주고 사용자가 RESET을 타이핑해야 진행한다.
저장소 구조
프레임워크의 동작은 대부분 파일 배치로 표현된다.
| 경로 | 역할 |
|---|---|
CLAUDE.md |
후보자 프로필 본문과 워크플로 규칙 |
.claude/commands/ |
11개 커맨드 정의 |
.claude/skills/job-application-assistant/ |
코어 지원 스킬. SKILL.md와 번호가 붙은 7개 지시 파일(instruction file) |
.claude/skills/job-scraper/ |
구직 검색 오케스트레이션 |
.claude/skills/upskill/ |
스킬 격차 분석과 학습 계획 |
.claude/settings.json |
Claude Code 권한 설정 (공유, 범위 한정) |
.agents/skills/ |
구직 포털 CLI 도구 6종 |
cv/main_example.tex |
moderncv 기반 CV 템플릿 (banking 스타일) |
cover_letters/ |
커스텀 cover.cls, 예시 커버레터, Lato와 Raleway 폰트를 담은 OpenFonts/ |
templates/ |
/add-template으로 등록한 커스텀 템플릿 |
documents/ |
/setup Path A와 /expand가 읽는 커리어 원자료 |
tools/ |
convert_salary_excel.py, lint_skills.py, security_guards.py |
salary_lookup.py |
연봉 벤치마킹 도구 |
job_search_tracker.csv |
지원 추적 스프레드시트 |
documents/ 폴더는 /setup의 Path A와 /expand가 읽는 원자료 저장소다. 하위 구조가 정해져 있어 사용자가 자료를 어디에 두어야 하는지가 명확하다.
| 하위 폴더 | 담는 자료 |
|---|---|
cv/ |
마스터 CV (PDF 또는 .tex) |
linkedin/ |
LinkedIn 프로필 export (PDF) |
diplomas/ |
학위 증명서와 성적 증명 |
references/ |
추천서 |
applications/ |
과거 지원 기록 (<company>_<role>/ 단위) |
applications/ 하위는 /outcome이 아카이브를 쓰는 자리이자 /setup Path A가 다시 읽는 자리다. 같은 폴더가 출력이자 입력이라 지원 기록이 쌓일수록 프로필이 정확해진다.
코어 스킬의 지시 파일 일곱 개가 지원서 품질을 결정한다.
| 파일 | 담는 내용 |
|---|---|
01-candidate-profile.md |
학력, 경력, 스킬 |
02-behavioral-profile.md |
PI, DISC 등 성향 평가 |
03-writing-style.md |
톤, 구조, 권장과 금지 |
04-job-evaluation.md |
fit 채점 프레임워크 |
05-cv-templates.md |
LaTeX CV 구조와 맞춤 규칙 |
06-cover-letter-templates.md |
커버레터 템플릿 |
07-interview-prep.md |
STAR 예시와 면접 프레임워크 |
보안 모델
구직 포털 공고는 신뢰할 수 없는 입력으로 다룬다. 워크플로는 공고 본문에 삽입된 지시를 따르지 않고, 본문 안의 링크도 fetch하지 않는다.
이 방어의 수준을 README는 분명히 한정한다. 방어가 지시 수준에 머물러 있고 샌드박스가 아니다. 그래서 낯선 구직 게시판을 쓸 때는 가져온 내용과 작성된 결과를 전송 전에 사람이 검토하라고 권한다. 세부는 SECURITY.md가 다룬다.
CI 쪽에도 별도 장치가 있다. tools/security_guards.py가 권한 allowlist, gitignore 규칙, manifest를 검사한다.
연봉 벤치마킹
연봉 도구는 사용자가 직접 제공하는 데이터로 동작한다. 노조 통계, Glassdoor export, 개인 조사 등 어떤 자료든 형식만 맞추면 된다. 형식과 설정은 tools/README_SALARY_TOOL.md가 안내한다. 연봉 데이터가 없으면 해당 단계는 그대로 건너뛰고 워크플로가 진행된다.
산출 품질을 좌우하는 요인
README는 산출물 품질의 가장 큰 단일 변수를 프로필의 상세도로 지목한다. 얇은 프로필은 일반적인 지원서를 만들고, 상세한 프로필이라야 실제로 맞춤화된 결과가 나온다.
- 직무 기술: 직함만 나열하지 않고 각 자리에서 실제로 한 일을 쓴다. 구체적 프로젝트, 사용한 도구, 책임 범위, 측정 가능한 성과를 담을수록 시스템이 경력을 다른 직무에 맞게 재구성할 여지가 커진다.
- 맥락 속 스킬: "Python"이나 "프로젝트 관리"처럼 나열하는 대신 어디에 어떻게 적용했는지 쓴다. "scikit-learn으로 고객 이탈 예측 ML 파이프라인을 구축했다"가 "Python, 머신러닝"보다 훨씬 많은 재료를 준다.
- 온보딩 경로는 모두 유효:
documents/폴더, CV 붙여넣기, 인터뷰 중 무엇을 쓰든 원리는 같다. 입력이 풍부할수록 산출이 날카로워진다.
구직 방식으로는 두 모드를 지원한다.
| 모드 | 전제 | 시스템의 역할 |
|---|---|---|
| explicit targeting | 원하는 직무나 섹터를 이미 안다 | fit을 기준으로 대상을 다듬고 우선순위를 매긴다 |
| latent opportunity discovery | 어떤 경로가 열려 있는지 모른다 | 직함이 아니라 실제로 한 일 전체를 분석해 고려하지 않았던 경로를 제시한다 |
두 번째 모드가 찾아내는 것은 예상 밖 산업으로 이어지는 전이 가능한 스킬, 즐겼거나 잘했던 일의 패턴, 도메인 전문성과 신기술이 결합된 신생 직무다. 이 모드를 살리려면 /setup 단계에서 경력만이 아니라 무엇이 활력을 주었고 무엇이 소모적이었으며 무엇을 더 하고 싶은지까지 서술해야 한다.
기여와 fork의 경계
이 프레임워크는 사용자마다 fork를 갖는 구조라, 어떤 변경이 본체로 돌아오고 어떤 변경이 fork에 남아야 하는지가 실제 문제가 된다. README는 PR을 고려하는 사람에게 먼저 CONTRIBUTING.md를 읽으라고 안내하며, 그 문서가 병합되는 변경과 fork에 남는 변경, 그리고 그 기준의 이유를 설명한다고 밝힌다.
/add-portal이 생성한 포털 스킬이 이 경계의 대표적인 예다. 생성된 스킬은 특정 시장 전용이라 사용자의 fork에 남고, 어느 시장에도 재사용되는 생성기 쪽이 본체에 유지된다.
결과
이 저장소는 벤치마크 수치를 제시하지 않는다. 대신 저자 본인의 실사용 결과를 근거로 든다.
| 항목 | 수치 |
|---|---|
| 맞춤 지원 | 69건 |
| 1차 면접 | 20건 |
| 계약 성사 | 1건 |
저자는 2026년 6월 AI 엔지니어로 입사했다. README는 대화한 모든 고용주에게 이 도구를 쓴다는 사실을 밝혔고, 감점 요인이 되기보다 기술적 대화를 여는 계기가 되는 경우가 많았다고 적는다. 지원 funnel 전체는 저자의 LinkedIn 글에 있다고 안내한다.
코드 품질은 CI가 검사한다.
| 검사 | 대상 |
|---|---|
| LaTeX smoke 컴파일 | cv/main_example.tex, cover_letters/cover_example.tex |
| 스킬 lint | tools/lint_skills.py가 스킬, 커맨드, settings.json 검사 |
| CLI 타입체크 | .agents/skills/ 아래 CLI 도구 |
README는 이 프로젝트가 Anthropic과 제휴, 승인, 후원, 유지보수 관계가 없는 독립 오픈소스 프로젝트임을 명시한다. Anthropic과 Claude Code는 이 워크플로가 쓰는 도구 체인을 설명하기 위해서만 언급한다. 연계된 암호화폐, 토큰, 유료 후원 프로그램이 없으며 그렇게 주장하는 것은 사기로 취급하라고 경고한다.
한계
| 한계 | 내용 |
|---|---|
| 덴마크 특화 포털 스킬 | 코어 워크플로는 언어와 국가에 무관하지만 기본 제공 포털 4종은 덴마크 시장 전용이다. 다른 나라 사용자는 /add-portal로 직접 스킬을 만들거나 linkedin-search와 freehire-search로 시작해야 한다 |
| LaTeX 의존 | CV와 커버레터가 LaTeX 기반이라 lualatex와 xelatex를 갖춘 배포판 설치가 필수다. 미니멀 TeX 배포판은 추가 패키지 설치가 필요하다 |
| 에이전틱 방어의 수준 | prompt injection 방어가 지시 수준에 머물러 완전한 샌드박스가 아니다. 낯선 포털에서는 사람이 결과를 검토해야 한다 |
| LinkedIn 스킬의 약관 리스크 | linkedin-search는 자동화 접근이 LinkedIn 이용약관에 어긋나 개인 사용과 저볼륨 사용을 전제로만 제공한다 |
| 인증 장벽 포털 미지원 | /add-portal은 인증이 필요한 포털을 거절한다 |
| PDF 검증의 토큰 비용 | 컴파일과 검사 루프가 반복 렌더링을 요구해, 토큰 절감을 위해 설계한 다른 부분의 절감분 일부를 다시 소비한다 |
핵심 용어
| 용어 | 뜻 |
|---|---|
| drafter-reviewer workflow | 초안 작성 에이전트와, 별도 컨텍스트로 스폰되어 비평만 담당하는 리뷰어 에이전트를 분리한 2단계 구조 |
| ATS | 이력서를 자동 파싱하고 필터링하는 채용 시스템. 렌더링된 페이지가 아니라 PDF의 내장 텍스트 레이어를 읽는다 |
| fit evaluation | 스킬, 경력, 조직문화, 위치, 커리어 정합성 다섯 항목으로 공고와 프로필의 적합도를 점수화하는 프레임워크 |
| honesty rule | 프로필이 뒷받침하지 않는 키워드는 CV에 채워 넣지 않고 격차로 남겨 두는 원칙 |
| relevance-weighted cutting | CV가 페이지 상한을 넘길 때 연관성, 고유성, 커버레터 의존도 점수로 잘라낼 줄을 고르는 방식 |
| system of record | 데이터의 정본이 어디에 있는지를 지정하는 개념. 이 프레임워크에서는 저장소 파일이 정본이다 |
관련 페이지
- Awesome Harness Engineering: CLAUDE.md와 커맨드와 스킬로 구성된 이 저장소의 구조가 harness engineering의 실사례에 해당한다
- gstack: AI-Powered Software Factory: Claude Code 슬래시 커맨드와 skill pack으로 도메인 워크플로 전체를 자동화하는 같은 패턴의 다른 사례
- Claude Code team just dropped a free course on loop engineering with Fable 5: 이 저장소가 사용하는 Claude Code의 스킬, 권한, 서브에이전트 스폰 메커니즘을 설명하는 강좌
- Agent Skills: 스킬을 절차 지식 패키지로 설계하는 원리.
.claude/skills/의 번호 붙은 지시 파일 구성이 이 원리를 따른다