# Jobberman — Agentic Job Search Assistant

An autonomous, AI-powered CLI tool that **scans job boards, scores relevance, tailors your resume, and applies** — all on autopilot, powered by Gemini.

```
       _       _     _
      | |     | |   | |
      | | ___ | |__ | |__   ___ _ __ _ __ ___   __ _ _ __
  _   | |/ _ \ | '_ \| '_ \ / _ \ '__| '_ ` _ \ / _` | '_ \
 | |__| | (_) | |_) | |_) |  __/ |  | | | | | | (_| | | | |
  \____/ \___/|_.__/|_.__/ \___|_|  |_| |_| |_|\__,_|_| |_|
```

---

## Features

| Feature | Description |
|---|---|
| **Autopilot Mode** | Continuously scans job boards, scores, tailors, and auto-applies |
| **Gemini-Powered Scoring** | Rates candidate–job fit 0–100 before wasting API calls |
| **Resume & Cover Letter Tailoring** | AI-generates tailored content per job description |
| **Portfolio Coaching** | Suggests projects to strengthen your application |
| **Mock Interview Prep** | Generates role-specific questions with feedback |
| **LinkedIn Auto-Apply** | Best-effort Easy Apply via Playwright automation |
| **Storage Management** | Auto-prunes packages, rotates logs for production |
| **Deduplication** | Never reprocesses the same job listing |

---

## Quick Start

### 1. Install

```bash
# Clone and install globally
git clone https://github.com/joey727/Jobberman && cd Jobberman
pip install -e .
```

### 2. Set Your API Key

```bash
export GEMINI_API_KEY="your-gemini-api-key"
```

Get one free at [Google AI Studio](https://aistudio.google.com/app/apikey).

### 3. Run a Single Job Analysis

```bash
job-search full \
  -j job_description.txt \
  -r resume.txt \
  --name "Jordan Doe" \
  --email "jordan@example.com" \
  --headline "Backend Engineer" \
  --years-experience 5 \
  --skills "Python, Django, PostgreSQL, AWS"
```

### 4. Start Autopilot 

```bash
job-search autopilot \
  --query "python backend" \
  --sources remoteok,remotive \
  --interval 30 \
  --min-score 60 \
  -r resume.txt \
  --name "Jordan Doe" \
  --email "jordan@example.com" \
  --headline "Backend Engineer" \
  --years-experience 5 \
  --skills "Python, Django, PostgreSQL"
```

This will:
1. **Scan** RemoteOK + Remotive every 30 minutes
2. **Score** each job against your profile (skip below 60/100)
3. **Tailor** your resume + cover letter for qualifying jobs
4. **Save** consolidated application packages to `autopilot_output/`
5. **Log** every action to `application_log.jsonl`

Stop with `Ctrl+C` — graceful shutdown guaranteed.

---

## Autopilot Output Structure

```
autopilot_output/
├── packages/
│   ├── 20260320T184500_senior-python-engineer.json    ← Single consolidated file
│   └── 20260320T185200_backend-developer-aws.json
├── applied_jobs.json       ← Dedup tracker (never reapply)
├── application_log.jsonl   ← Structured action log
└── application_log.old.jsonl  ← Rotated archive
```

Each package JSON contains the job description, score, tailored resume, and cover letter in one file.

### Storage Management Flags

| Flag | Default | Description |
|---|---|---|
| `--max-packages` | 50 | Auto-delete oldest packages beyond this limit |
| `--max-log-lines` | 5000 | Rotate log file when exceeding this line count |

---

## All CLI Commands

| Command | Description |
|---|---|
| `job-search full` | Single job: parse JD → tailor resume → portfolio → interview |
| `job-search autopilot` | Continuous bot: scan → score → tailor → apply → log |
| `job-search run` | Batch scan from a source + tailor per job |
| `job-search apply` | LinkedIn Easy Apply from generated packages |
| `job-search apply-and-reach-out` | Apply + resolve company + collect contacts + draft emails |
| `job-search collect-contacts` | Scrape LinkedIn employee profiles |
| `job-search message-contacts` | Draft and optionally send outreach emails |
| `job-search export-auth` | Export Playwright authenticated session |
| `job-search --version` | Print version |

---

## LinkedIn Automation (Optional)

For LinkedIn auto-apply and contact scraping:

```bash
# 1. Install Playwright
python3 -m playwright install

# 2. Export your LinkedIn session
job-search export-auth \
  --login-url "https://www.linkedin.com/login" \
  --output-path storage_state.json

# 3. Use with autopilot
job-search autopilot \
  --query "python" \
  --storage-state storage_state.json \
  -r resume.txt --name "Jordan Doe" ...
```

> **Safety**: LinkedIn Easy Apply submissions are auto-confirmed in autopilot mode. Manual apply commands still prompt for confirmation.

---

## Tests

All 32 tests pass with no API key required (Gemini calls are fully mocked):

```bash
pip install pytest
pytest tests/ -v
```

| Test File | Coverage |
|---|---|
| `test_models.py` | All 11 Pydantic models |
| `test_scoring.py` | Relevance scorer |
| `test_bot.py` | Bot loop, dedup, logging, pruning |
| `test_agents.py` | All 4 agents |

---

## Project Structure

```
job_search_agent/
├── agents/          # Gemini-powered agents (parser, tailor, portfolio, interview)
├── automation/      # Playwright automation (LinkedIn apply, contacts, email)
├── sources/         # Job board scanners (RemoteOK, Remotive, WeWorkRemotely)
├── bot.py           # Autonomous daemon loop
├── scoring.py       # Gemini relevance scorer
├── models.py        # Pydantic data models
├── orchestrator.py  # Multi-agent pipeline coordinator
├── cli.py           # CLI entry point
└── terminal_ui.py   # Rich terminal rendering
tests/               # Pytest suite (32 tests)
```

---

## Deployment

### Install from GitHub (Any Machine)

```bash
pip install git+https://github.com/joey727/Jobberman.git
```

That's it — `job-search` is now available globally. No cloning needed.

### Install with pipx (Isolated Environment)

```bash
pipx install git+https://github.com/joey727/Jobberman.git
```

### With LinkedIn Automation Support

```bash
pip install "jobberman[linkedin] @ git+https://github.com/joey727/Jobberman.git"
python3 -m playwright install
```

### Publish to PyPI (Maintainer)

```bash
pip install build twine
python3 -m build
twine upload dist/*
```

Once published, anyone can install with:
```bash
pip install jobberman
```

---

## Limitations

- LinkedIn DOM selectors change frequently — you may need to tweak automation selectors.
- Employee scraping and email extraction are best-effort.
- Screenshots are captured for diagnosing automation failures.
- This is automation scaffolding — always review outputs before sending.

## License

MIT
