SHOBR — Simulate Human Occupational-Bureaucratic Rituals

SHOBR 저장소는 브라우저 자동화를 이용하는 구직 CLI 도구다. 제작자는 이를 ‘해커가 과정에 참여하는 방식(Hacker-in-the-Loop)’의 구직 자동화 도구라고 소개한다.

소개와 설계

제작자는 2026년 구직 시장에 여러 구직 지원 자동화 도구가 있으며, 자유·오픈소스 소프트웨어(FOSS)도 있다고 설명한다. SHOBR은 브라우저 자동화에 beachpatrol을, 이력서 파일 관리에 roffume을 사용한다.

SHOBR은 헤드리스 브라우저 대신 사용자가 평소 쓰는 브라우저를 자동 조작한다. beachpatrol을 통해 로그인된 브라우저로 LinkedIn을 둘러보며, 제작자는 이 방식이 일반적인 사용자 클릭과 거의 같아 보일 것이라고 말한다. 단, 이용자가 서비스 약관을 위반하지 않는 경우라는 조건을 단다.

도구는 지원서 제출을 자동화하지 않는다. SHOBR이 초안을 작성하고 PDF를 만들며 정보를 확인하지만, 최종 제출은 이용자가 직접 한다. 제작자는 이를 무차별 지원 방식과 구분한다.

이력서를 직무에 맞게 다듬는 데에는 LLM이 필요하다고 보고, SHOBR은 LLM 사용을 가능한 한 줄이도록 설계했다. 다른 도구와 달리 에이전트 구동을 요구하지 않는다. 더 많은 기능이 필요하다면 SHOBR 위에 SKILL이나 MCP 서버를 만들 수 있다고 설명한다.

LLM 제공자에 종속되지 않도록 any-llm 추상화 계층을 사용한다. OpenAI, Anthropic, 로컬 모델을 이용할 수 있으며, faaah를 통해 로컬에서 이용 가능한 LLM 에이전트 구독을 연결하는 방법도 제시한다.

발견한 채용 공고, 심사 결과, 지원 현황 등은 추가만 가능한 JSONL 이벤트 로그에 저장하고, 이를 바탕으로 현재 상태 파일을 만든다. 파이프라인을 중단하거나 새 규칙으로 후보 승인 여부를 다시 계산해도 데이터가 사라지지 않는다고 설명한다.

이력서는 Markdown으로 조정한 뒤 Groff와 Pandoc을 거쳐 지원자 추적 시스템(ATS)이 읽을 수 있는 PDF로 만든다. 산출물은 지원 건별 폴더에 저장한다. 제작자는 표준 라이브러리의 unittest를 이용한 전체 흐름 레드-그린 테스트 주도 개발(TDD)을 적용했고, 주석을 포함해 작성 시점에 3,500줄이라고 소개한다. ‘바이브 코딩’으로 만든 프로젝트가 아니라고도 강조한다.

설치와 초기 설정

필수 조건은 beachpatrol이다. 제작자는 이를 일상적으로 사용하는 브라우저처럼 쓸 수 있으면서도, Playwright 래퍼 방식으로 자동화할 수 있는 브라우저라고 설명한다. 구직 검색에는 정보 수집이 필요하고, 로그인된 인증 정보를 사용하려면 실제 브라우저를 활용하는 편이 낫다는 것이 이 도구가 이를 선택한 이유다. 다른 구직 자동화 도구는 인증되지 않은 요청이나 헤드리스 브라우저를 사용하거나, 인증 정보를 자동화 브라우저로 복사하도록 요구할 수 있다고 설명한다.

beachpatrol README에서 자세한 내용을 확인할 수 있다. beachpatrol 설정을 마친 뒤에는 Python 3.14 이상과 uv가 필요하다.

text
git clone https://github.com/sebastiancarlos/shobr
cd shobr
uv sync # install the single runtime dependency, `any-llm-sdk[openai]`
uv tool install . # Put the `shobr` CLI on `PATH`
shobr --help

Markdown 이력서를 PDF로 변환하는 roffume를 위해 Unix 텍스트 처리 도구 groff와 pandoc도 설치해야 한다.

초기 설정은 다음 순서로 진행한다.

  • shobr setup을 실행하면 $XDG_CONFIG_HOME/shobr/config.toml에 설정 파일을 만들고 프로필 템플릿을 준비한다. 또한 SHOBR의 beachpatrol 명령을 예상 폴더에 심볼릭 링크해 beachpatrol에서 사용할 수 있게 한다. 생성된 설정 파일을 작성한다.
  • LinkedIn에 로그인된 beachpatrol 프로필을 하나 준비하고, 프로필 이름을 config.toml의 beachpatrol_profile 항목에 지정한다.
  • LLM을 쓰는 단계에서는 any-llm-sdk가 환경 변수 OPENAI_API_KEY, SHOBR_AI_MODEL, OPENAI_BASE_URL에서 제공자 키 등을 읽는다. any-llm-sdk를 통해 원하는 LLM API 제공자를 쓸 수 있으며, faaah로 로컬에서 사용할 수 있는 LLM 에이전트 구독을 연결할 수도 있다.
  • 기본 이력서를 읽는 단계에는 환경 변수 SHOBR_MAIN_CV_PATH로 경로를 지정할 수 있다.
  • 이력서를 작성하고 지원별 디렉터리를 만들려면 CV 툴체인을 설정해야 한다. 처음 tailor 단계에 도달하면 SHOBR이 최신 roffume 릴리스를 ~/shobr-resumes에 복제하도록 제안한다. 이미 체크아웃한 경로가 있다면 config.toml의 cv_toolchain_dir로 지정할 수 있다. 이 디렉터리에는 이력서 변형의 입력과 출력이 저장된다. 기본 이력서는 <cv_toolchain_dir>/resume.md이며, SHOBR_MAIN_CV_PATH 환경 변수나 main_cv_path 설정으로 경로를 바꿀 수 있다.

CLI와 파이프라인

구직 과정은 다섯 단계로 나뉜다. shobr status는 각 단계의 상세 상태를 보여준다. shobr next는 단계별 하위 명령을 직접 실행하는 대신 파이프라인에서 다음에 할 일을 자동으로 제안한다.

예시 상태 출력은 다음과 같다.

text
$ shobr status

- DISCOVERY
 - Total Leads Found: 59
 - Rejected by Filter: 10
 - Pending Enrichment: 3

- ENRICHMENT
 - Total Enriched: 48
 - Rejected by Filter: 2
 - Pending Screening: 24

- SCREENING
 - Total Screened: 45
 - Skipped: 6
 - Lacking LLM Review: 1
 - Pending Human Review: 23
 - LLM Scores: Human Scores:
 5: 11 5: 2 (1 to tailor)
 4: 9 4: 6 (5 to tailor)
 3: 9 3: 4 (4 to tailor)
 2: 8 2: 4 (4 to tailor)
 1: 8 1: 6
 - Pending Tailoring: 14

- TAILORING
 - Packages Built: 2
 - Pending Review: 0

- TRACKING
 - Applied: 2
 - Interviewing: 0
 - Offer: 0
 - Rejected: 0
 - Ghosted: 0
 - Withdrawn: 0

발견

config.toml에 설정한 키워드와 지역을 바탕으로 LinkedIn 검색 결과를 수집하고, 기본 정규식 사전 필터를 적용한다.

  • shobr discovered는 새로 가져오지 않고 저장된 후보 공고 요약을 출력한다.
  • shobr discover는 beachpatrol을 실행해 공고를 검색하고 수집한다.
  • shobr discover <posting_id-or-URL>은 검색 없이 지정한 공고를 수동 후보로 추가한다.

상세 정보 수집

각 공고 페이지를 방문해 전체 설명, 급여 범위, Easy Apply 링크를 추출한다. 요청 속도를 조절하고 제한을 피하려고 한 번에 한 공고씩 처리한다.

  • shobr enriched는 상세 정보를 수집한 공고를 출력한다.
  • shobr enrich-next는 아직 처리하지 않은 후보 가운데 가장 오래된 공고의 상세 페이지를 가져온다.
  • shobr enrich-all은 처리 대기 중인 모든 후보를 가져온다. 상세 페이지 사이에는 기본 10초 대기하며, --delay SECONDS로 시간을 바꿀 수 있다. 최소 대기 시간은 1초이고, 처음 실패가 발생하면 중단한다.
  • shobr enrich <posting_id>는 지정한 공고의 정보를 가져온다.

심사

개인 Markdown 프로필과 거부 기준을 토대로 상세 정보를 수집한 공고를 평가한다.

  • shobr screen-llm-next는 LLM에 다음 후보의 점수(1~5)와 평가 이유를 작성하게 한다.
  • shobr screen-llm-all은 아직 점수가 없는 후보 전체를 일괄 평가한다.
  • shobr screen-next는 다음 후보에 대한 이용자의 판정을 기록한다. 점수(1~5)와 이유를 $EDITOR에서 작성하거나 --score 및 --reason으로 지정한다.

이력서 맞춤화

‘추진(Pursue)’으로 표시한 공고에 대해 LLM이 기본 resume.md를 고쳐 관련 기술을 강조한다. 이어 roffume 툴체인(Groff/Pandoc)으로 한 페이지에 들어가는지 확인하고, 넘치면 다시 작성한다.

  • shobr tailor-next는 다음 지원 대상 공고에 맞춘 이력서와 자기소개서를 만든다.
  • shobr tailor-all은 아직 지원 패키지가 없는 추진 대상 공고의 패키지를 모두 만든다.
  • shobr tailored는 생성된 패키지를 출력한다.

지원 현황 추적

지원 현황은 로컬 칸반 스타일로 관리한다.

  • shobr track <posting_id> <status> [--note TEXT]는 지원 상태를 갱신한다. 상태에는 applied, interviewing, offer, rejected 등이 있다.
  • shobr tracked는 전체 지원 흐름의 개요를 출력한다.

설정과 이력서

SHOBR이 이용자에 관해 저장하는 설정은 $XDG_CONFIG_HOME/shobr/ 아래에 있다. 기본 경로는 ~/.config/shobr이며, config.toml 하나와 profile/*.md 폴더로 구성된다. shobr setup은 안내가 포함된 템플릿을 만든다.

text
config.toml      # filter rules, geo map, toolchain + browser wiring
profile/   user-detail.md fit-criteria.md deal-breakers.md   # screen-llm inputs   resume-guide.md cover-guide.md                    # tailor-only inputs

프로필 폴더의 기본 경로는 $XDG_CONFIG_HOME/shobr/profile이다. profile_dir 설정으로 다른 위치를 지정할 수 있다.

cv_toolchain_dir은 필수 설정이며, CV 툴체인(roffume Git 체크아웃)의 위치를 가리킨다.

text
cv_toolchain_dir = "~/shobr-resumes"

기본 이력서 경로는 <cv_toolchain_dir>/resume.md이며 main_cv_path로 바꿀 수 있다. 이 디렉터리에는 생성한 이력서와 그 밖의 데이터가 지원별 내부 디렉터리에 저장된다.

profile_dir은 선택 설정이며 기본값은 $XDG_CONFIG_HOME/shobr/profile이다.

text
profile_dir = "~/.config/shobr/profile"

main_cv_path도 선택 설정이며 기본값은 <cv_toolchain_dir>/resume.md다.

text
main_cv_path = "~/shobr-resumes/resume.md"

beachpatrol_profile은 필수 설정으로, LinkedIn에 로그인된 beachpatrol 브라우저 프로필을 지정한다.

text
beachpatrol_profile = "job-hunter"

beachpatrol_browser는 조작할 브라우저를 지정하며 기본값은 "chromium"이다.

text
beachpatrol_browser = "chromium"

제작자는 Chromium을 권장한다. Firefox도 작동하지만 스텔스 플러그인이 약해 LinkedIn에서 오류가 더 자주 발생할 수 있다고 설명한다. 자세한 내용은 beachpatrol의 알려진 문제를 참고하면 된다.

titles는 필수 문자열 목록이다. LinkedIn 검색에서 OR로 묶이는 직함 키워드를 지정한다.

text
titles = ["Technical Lead", "Software Engineer", "Senior Software Engineer"]

workplace_types는 선택 문자열 목록으로, 같은 OR 검색어에 추가한다. 가능한 값은 on-site, hybrid, remote다.

text
workplace_types = ["on-site", "hybrid", "remote"]

geo는 선택 문자열 목록으로 검색 지역을 지정한다. 지역은 [geo_ids] 맵에 있는 이름으로 참조한다.

text
geo = ["new-york-city", "san-francisco-bay-area"]

[geo_ids]는 선택 테이블이며, 이름마다 숫자만으로 된 ID를 지정한다.

text
[geo_ids]
new-york-city = "111111111"
san-francisco-bay-area = "222222222"

각 지역 이름을 LinkedIn의 geoId에 연결한다. 이름은 자유롭게 정할 수 있지만 실제 지역을 나타내야 한다. 특정 지역을 검색한 뒤 LinkedIn 채용 정보 URL의 geoId=에서 ID를 직접 확인해야 한다. LinkedIn은 도시와 대도시권처럼 한 지역에 여러 ID를 두는 경우가 있다.

reject_employment_type는 선택 문자열 목록이며 비워 둘 수 있다. 채용 형태에 따라 공고를 거부한다. 가능한 값은 Full-time, Part-time, Contract, Temporary, Internship이다.

text
reject_employment_type = ["Internship"]

presence_locations는 선택 목록이며 비워 둘 수 있다. 현장 출근이 필요한 일자리에서 허용할 지역을 지정한다. 지역명은 대소문자를 구분하지 않고 문자열 그대로 비교한다. 원격 공고는 어느 지역에서든 통과하지만, 현장 근무와 하이브리드 공고는 지정한 지역을 명시해야 한다.

text
presence_locations = ["New York"]

stale_after_days는 마지막 상세 정보 확인 이후 후보가 오래된 것으로 간주되기까지의 일수다. 기본값은 2다. 오래된 후보는 아직 채용 중인지 확인하도록 다시 수집하는 것이 중요하다고 설명한다. 심사와 이력서 맞춤화 등 비용이 드는 작업은 --force를 지정하지 않으면 오래된 행을 처리하지 않는다.

text
stale_after_days = 2

reject_recent_application_days는 선택 정수 설정으로, 기본값 0은 기능을 끈 상태다. 후보를 마지막으로 확인한 시점에서 지정한 일수 안에 해당 회사에 이미 추적 중인 지원이 있으면 후보를 거부한다.

text
reject_recent_application_days = 90

[reject_title]은 선택 테이블이다. 레이블마다 Python 정규식을 지정하고, 공고 제목에 사전 필터를 적용한다. 일치한 후보는 title contains '<label>' 사유로 거부된다.

text
[reject_title]
golang = "\\bgolang\\b"
devops = "\\bdevops\\b"

[providers.<name>]을 이용하면 사용자 지정 채용 사이트 제공자를 코드에 추가할 수 있다. 기본 지원은 LinkedIn뿐이며, 제공자 인터페이스는 src/shobr/providers/base.py에 정의돼 있다. 새 제공자를 추가했다면 이 TOML 설정 형식으로 전역 설정을 덮어쓸 수 있다. 모든 CLI 명령은 --provider <name> 옵션을 지원하며, 기본 제공자는 LinkedIn이다.

LLM 단계는 프로필을 일반 Markdown 파일로 읽는다. shobr setup으로 프로필 템플릿을 초기화한 다음 직접 작성한다. 기본 이력서는 심사와 맞춤 이력서 생성의 바탕으로 쓰며, 경로는 SHOBR_MAIN_CV_PATH, main_cv_path, <cv_toolchain_dir>/resume.md 순으로 정한다.

프로필 템플릿의 역할은 다음과 같다.

CV 툴체인과 파일 저장 방식

SHOBR은 CV 툴체인 roffume에 의존한다. 첫 tailor 실행 때 고정된 릴리스를 ~/shobr-resumes에 복제하도록 제안한다.

roffume가 코드에 고정된 것은 아니다. SHOBR은 cv_toolchain.py의 추상 클래스 CvToolchain에 정의된 네 메서드(scaffold, build, page_check, finalize)를 통해 툴체인과 통신한다. 이 인터페이스를 구현하는 도구라면 약간의 포크와 코드 수정으로 roffume 대신 사용할 수 있다.

text
<cv_toolchain_dir>/        # default: ~/shobr-resumes
  resume.md                # default main resume (see main_cv_path)
  resume.pdf               # built main resume
  applications/<slug>/     # one per tailored posting
    resume.md              # tailored resume (rewritten until it fits one page)
    cover-letter.md        # generated cover letter
    notes.md               # source posting URL
    *.pdf                  # built outputs

SHOBR은 표준 데이터베이스 대신 이벤트 소싱 방식을 사용한다. 파이프라인 각 단계의 events.jsonl 로그는 추가만 가능하며, 로그를 재생해 현재 상태를 담은 .json 파일을 만든다.

text
notifications/ events.jsonl -> notifications.json  # Notification queue
discovery/     events.jsonl -> discovery.json      # Discovery stage
enrichment/    events.jsonl -> enrichment.json     # Scraped job details
screening/     events.jsonl -> screening.json      # LLM and Human scores
tailoring/     events.jsonl -> tailoring.json      # CV generation status
tracking/      events.jsonl -> tracking.json       # Kanban funnel status
smoke/         linkedin-homepage.html              # smoke-test-browser dump

애플리케이션 데이터는 $XDG_DATA_HOME/shobr/에 둔다.

text
shobr/
  pyproject.toml
  README.md
  test.py                   # E2E test suite
  test-fixtures/            # synthetic HTML fixtures (fake data) backing the E2E tests
  src/shobr/
    beachpatrol-commands/   # beachpatrol commands (.js files)
    templates/              # LLM prompts, profile scaffolds, config default
    core.py                 # cross-functional core
    cli.py                  # argument parsing + entry point
    browser.py              # beachpatrol integration
    ai.py                   # Minimal LLM-provider integration
    notification.py         # notifications (unwired lead source, not a stage)
    discovery.py            # discovery stage
    enrichment.py           # enrichment stage
    screening.py            # screening stage
    tailoring.py            # tailoring stage (CV toolchain contract)
    tracking.py             # tracking stage
    pipeline.py             # next/dispatcher
    config.py               # config.toml loading + validation
    color.py                # terminal palette

한계와 보안 고려사항

SHOBR은 LinkedIn만 지원한다. 다른 제공자를 추가하려면 수요가 있을 때 코드의 추상화를 확장할 수 있다고 제작자는 말한다. LinkedIn의 페이지 구조가 바뀌면 데이터 추출이 깨질 수 있다. 추출은 data-testid, 카드 키, 아이콘 등 LinkedIn 마크업에 의존한다. 구조가 바뀌면 명령은 오류를 명확히 내고 아무것도 쓰지 않도록 설계했다고 설명한다.

beachpatrol은 필수이며, 인증되지 않은 모드나 헤드리스 모드는 없다. LinkedIn에 로그인된 실제 브라우저가 필요하다. 데이터는 데이터베이스가 아니라 단순 JSON 파일에 저장된다. 스케줄러도 없으며, next 등의 명령은 한 번 실행할 때마다 수동으로 처리한다. 필요하다면 cron이나 systemd 타이머 등으로 자동화할 수 있다고 안내한다.

LinkedIn 약관 위반 위험은 이용자가 감수해야 한다. 로그인된 일상용 브라우저를 자동화하는 방식이라도 약관에 어긋날 수 있다. 제작자는 속도를 조절하고 사람 수준의 처리량을 유지하라고 권한다. 예를 들어 shobr next 같은 명령은 한 번 실행할 때 수집 작업을 최대 하나만 수행한다.

이력서와 profiles/ 정보가 제3자에게 전송될 수 있다. screen-llm과 tailor는 이력서, 프로필 문서, 공고 내용을 any-llm-sdk가 연결한 LLM 제공자에게 보낸다. 여기에는 이름, 경력, 지역 범위가 포함되며 다른 회사의 서버에 전달된다. 제작자는 상대적으로 덜 위험하다고 판단하는 제공자나 로컬 모델을 고려하라고 안내한다.

SHOBR은 LinkedIn 비밀번호나 세션 토큰을 요구하지 않는다. 인증 정보는 전부 beachpatrol을 통한 일상용 브라우저 안에 남는다.

비슷한 도구

  • career-ops는 별점 약 7만2천 개를 받은 Markdown·파일시스템 기반 스킬 모음으로, 코딩 에이전트가 불러와 쓴다. 사람의 참여를 전제로 점수 매기기, 이력서 맞춤화, 면접 준비를 지원한다. SHOBR과 매우 비슷하지만, career-ops는 에이전트가 브라우저를 조작하는 데 의존하는 대신 SHOBR이 자체 브라우저 자동화 구성을 제공한다고 제작자는 비교한다. SHOBR은 CLI 중심이며 LLM 사용을 제한하고, 에이전트가 아니라 프로그램 코드가 작업을 조정한다.
  • 상용 서비스 Morning Stack은 밤사이 채용 사이트를 수집하고 공고가 여전히 유효한지 확인하며, 맞춤 이력서를 사실 확인한 뒤 아침에 결과를 제공한다. SHOBR도 결과를 준비한 뒤 사람이 제출하는 방식을 따르지만, 대화식으로 실행하고 이용자의 인증 브라우저를 쓴다. 공고가 여전히 열려 있는지는 확인하지 않으며 LinkedIn이 이를 판단해 표시한다고 가정한다.
  • 상용 브라우저 확장 프로그램 Simplify는 저장된 프로필로 지원 양식을 자동 입력하고 제출은 이용자가 클릭한다. SHOBR은 지원 양식을 자동 입력하지 않는다. 최종 지원 절차는 이용자나 브라우저의 자동 완성 기능이 처리한다.
  • AIHawk는 별점 약 3만 개를 받은 LLM 기반 지원 봇으로, 수정된 Playwright 포크를 사용해 대량으로 지원서를 자동 제출한다. 채용 담당자의 받은 편지함을 어지럽힌다는 온라인 반발과 LinkedIn의 중단 요구를 받았고, 이에 코드 기능이 축소됐다고 소개한다. SHOBR은 중단 요구를 피하기 위해 자동 제출을 하지 않는다고 설명한다.
  • JobSpy는 TLS 지문을 흉내 내는 HTTP 기반 채용 사이트 수집 도구로, 브라우저를 사용하지 않는다. 스키마 문서화가 잘 돼 있다고 소개한다. SHOBR은 실제 브라우저 세션으로 공고를 찾는다.
  • browser-use는 별점 약 11만 개를 받은 범용 브라우저 에이전트 프레임워크로, 구직 전용은 아니다. 제작자는 직접 비교할 만한 도구로 beachpatrol을 든다.

SHOBR의 라이선스는 MIT다.