# Boss Resume Downloader

> |

- **Type:** Skill
- **Install:** `agentstack add skill-1xiaoyueryuer-boss-hr-agent-toolkit-boss-resume-downloader`
- **Verified:** Pending review
- **Seller:** [1xiaoyueryuer](https://agentstack.voostack.com/s/1xiaoyueryuer)
- **Installs:** 0
- **Category:** [Agent Skills](https://agentstack.voostack.com/c/agent-skills)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [1xiaoyueryuer](https://github.com/1xiaoyueryuer)
- **Source:** https://github.com/1xiaoyueryuer/boss-hr-agent-toolkit/tree/main/boss-resume-downloader

## Install

```sh
agentstack add skill-1xiaoyueryuer-boss-hr-agent-toolkit-boss-resume-downloader
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Boss Resume Downloader

## Purpose

Install and operate a deterministic BOSS/Zhipin recruiter resume synchronization workflow. Standardize the boss-agent-cli command path, CDP endpoint, Chrome launch convention, auth data directory, resume storage root, and resume download fallback logic so that the workflow is reproducible across machines and across agent harnesses (Claude Code, Claude Desktop, Cursor, etc.).

Use this skill for two related goals:

1. Speed up installation and first successful run on a new machine.
2. Let other sessions operate the same BOSS resume synchronization flow without rediscovering CDP paths, Chrome executable locations, boss-agent-cli storage directories, or `securityId` fallback behavior.

## Golden Configuration

Prefer these defaults unless the user explicitly requests otherwise. Paths shown with `~` are POSIX (macOS/Linux); the Windows equivalent uses `%USERPROFILE%`.

| Item | Value (POSIX) | Value (Windows) |
|------|---------------|-----------------|
| Platform | `zhipin` | `zhipin` |
| Role | `recruiter` | `recruiter` |
| CDP URL | `http://localhost:9222` | `http://localhost:9222` |
| boss command | `boss` (on PATH) | `boss` (on PATH) or `%USERPROFILE%\bin\boss.cmd` |
| boss-agent-cli auth data dir | `~/.boss-agent` | `%USERPROFILE%\.boss-agent` |
| Resume output root | `~/WorkBuddy/boss-resumes` | `%USERPROFILE%\WorkBuddy\boss-resumes` |
| Sync script | `scripts/sync_boss_resumes.py` (relative to this SKILL.md) | same |

Invoke the CLI like this (assumes `boss` is on PATH):

```bash
boss --role recruiter --platform zhipin --cdp-url http://localhost:9222 
```

Important known facts:

- Use platform `zhipin`, not `zhipin-recruiter`.
- Use CDP URL `http://localhost:9222` when recruiter authentication is needed.
- Use auth data directory `~/.boss-agent` (POSIX) / `%USERPROFILE%\.boss-agent` (Windows). Do not guess `.boss-agent-cli`.
- On Windows, if `boss` is not resolvable from subprocess, fall back to `%USERPROFILE%\bin\boss.cmd`.
- Resume viewing requires encrypted geek ID, encrypted job ID, and `securityId`.
- `hr applications` can list applied candidates but may not expose `securityId` in all outputs.
- `hr chat` can expose candidate names but may still omit `securityId`.
- The bundled script can use boss-agent-cli internal `friend_detail(friendIds)` as a fallback to resolve `securityId` from numeric `friendId`. This fallback requires the `boss_agent_cli` Python package to be importable from the active environment.
- `hr candidates` can be used as an additional fallback source.
- Do not assume `encryptFriendId` equals `securityId`.

## Recommended Usage Pattern: Hourly Incremental Sync + Local Analysis

**Strongly recommended over one-shot bulk downloads.**

### Schedule hourly incremental sync via agent

Use your agent harness's scheduled task capability (e.g., Claude Code `/loop`, cron, or any recurring job) to run `sync-all` every hour:

```bash
# Run once per hour, keep Chrome open in the background
python "${SKILL_DIR}/scripts/sync_boss_resumes.py" sync-all
```

In Claude Code you can set this up with:

```
/loop 1h python "${SKILL_DIR}/scripts/sync_boss_resumes.py" sync-all
```

Each run only downloads candidates not yet in `candidate_index.json`, so an hourly job downloads at most the few new applicants from the past hour — typically 1–5 requests per run.

**Why this is better than a one-shot bulk sync:**

1. **Avoids risk control.** BOSS/Zhipin detects abnormal access patterns. Downloading 50+ resumes in one session looks like scraping and may trigger a temporary block or CAPTCHA. Spreading the same work across 24 hourly runs of 1–3 resumes each is indistinguishable from normal recruiter browsing.

2. **Local analysis is fast and free.** Once resumes are on disk as `resume.md`, any analysis (filtering by keyword, comparing candidates, summarizing, ranking) runs entirely locally — no network round-trips, no rate limits, no extra API calls to BOSS.

### Analyze from local Markdown files

After sync, all resumes are at:

```
~/WorkBuddy/boss-resumes/jobs/_/resumes/_/resume.md
```

To analyze them, read the local files directly. Example prompts that work well once files are synced:

- "Read all resume.md files under ~/WorkBuddy/boss-resumes and shortlist candidates with Python experience."
- "Compare the work experience sections across all downloaded resumes for job ."
- "Find candidates who mentioned crawler/scrapy/selenium in their resumes."

This is faster and more reliable than querying BOSS live for each analysis question.

---

## First-Time Setup Checklist

### 1. Verify the boss CLI is available

```bash
boss --help
```

If `boss` is not on PATH, locate the installed entrypoint and either add it to PATH or pass it via `--boss-bin` to the bundled script. On Windows the entrypoint is typically `%USERPROFILE%\bin\boss.cmd` (a wrapper around the env's `boss.exe`).

### 2. Start Chrome with a stable CDP endpoint

Prefer an already-running Chrome session that exposes `http://localhost:9222`. If status checks fail because CDP is unavailable, launch Chrome manually with remote debugging enabled and a dedicated profile. Common executable locations:

- macOS: `/Applications/Google Chrome.app/Contents/MacOS/Google Chrome`
- Linux: `google-chrome` or `chromium` on PATH
- Windows: `C:\Program Files\Google\Chrome\Application\chrome.exe`, `C:\Program Files (x86)\Google\Chrome\Application\chrome.exe`, or `%LOCALAPPDATA%\Google\Chrome\Application\chrome.exe`

Recommended launch shapes:

```bash
# macOS
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \
  --remote-debugging-port=9222 \
  --user-data-dir="$HOME/.workbuddy/chrome-profiles/boss-cdp"

# Linux
google-chrome \
  --remote-debugging-port=9222 \
  --user-data-dir="$HOME/.workbuddy/chrome-profiles/boss-cdp"
```

```bat
:: Windows
"" --remote-debugging-port=9222 --user-data-dir="%USERPROFILE%\.workbuddy\chrome-profiles\boss-cdp"
```

Do not randomize the CDP port or profile directory unless port 9222 is occupied.

### 3. Verify recruiter login

```bash
boss --role recruiter --platform zhipin --cdp-url http://localhost:9222 status
```

If not logged in, run CDP login and let the user complete any browser-side QR/login step:

```bash
boss --role recruiter --platform zhipin --cdp-url http://localhost:9222 login --cdp
```

### 4. Verify online jobs

```bash
boss --role recruiter --platform zhipin --cdp-url http://localhost:9222 hr jobs list
```

Proceed only after the command returns the expected recruiter jobs.

## Default Storage

Use this default resume root unless the user specifies another directory:

- POSIX: `~/WorkBuddy/boss-resumes`
- Windows: `%USERPROFILE%\WorkBuddy\boss-resumes`

Expected structure:

```text
boss-resumes/
  config.json
  job_index.json
  jobs/
    _/
      job.json
      candidate_index.json
      resumes/
        _/
          resume.json
          resume.md
          raw_response.json
```

## Main Workflow

### 1. Check login and open jobs

Run status first. If authentication is missing or expired, use the CDP login flow.

```bash
boss --role recruiter --platform zhipin --cdp-url http://localhost:9222 status
boss --role recruiter --platform zhipin --cdp-url http://localhost:9222 hr jobs list
```

Persist all currently online jobs into `job_index.json`, keyed by stable job ID and encrypted job ID.

### 2. Create per-job directories

For every online job, create a directory named:

```text
_
```

Store raw job metadata in `job.json`.

### 3. List applied candidates

For each job, call applications with the encrypted job ID when available:

```bash
boss --role recruiter --platform zhipin --cdp-url http://localhost:9222 hr applications --job-id 
```

Paginate if the CLI output indicates more pages.

### 4. Resolve resume parameters

For each applied candidate, resolve:

- `encryptGeekId` / encrypted candidate ID
- display name
- `securityId`
- applicable encrypted job ID

Use `applications` first. If `securityId` is absent, resolve it by numeric `friendId` through the internal boss-agent-cli `friend_detail(friendIds)` API. This endpoint returns candidate name, `securityId`, `encryptUid`, `jobId`, and `encryptJobId`. Use `hr candidates` or `hr chat` only as additional fallback sources. Do not assume `encryptFriendId` equals `securityId`.

If `securityId` cannot be resolved, record the candidate as `pending_security_id` in `candidate_index.json` and skip resume download for that candidate. Do not mark as permanently failed.

### 5. Download online resume

When all parameters are present, call:

```bash
boss --role recruiter --platform zhipin --cdp-url http://localhost:9222 hr resume  --job-id  --security-id 
```

Save:

- raw JSON response as `raw_response.json`
- normalized JSON as `resume.json`
- readable Markdown resume as `resume.md`

### 6. Incremental behavior

Before downloading, inspect `candidate_index.json`.

Skip a candidate when:

- candidate ID exists in the index,
- resume status is `downloaded`, and
- no `--force` option was requested.

Update candidates when:

- candidate is new,
- previous status was `pending_security_id`, `failed`, or `partial`,
- `--force` is set.

### 7. Random delay

During bulk downloads, apply a random delay between successful/attempted candidate downloads:

```text
3-6 seconds
```

Do not delay for dry-run/list-only operations.

## Bundled Script

The script lives next to this SKILL.md at `scripts/sync_boss_resumes.py`. Resolve `${SKILL_DIR}` to the directory containing this SKILL.md, then call:

```bash
# Sync all online jobs incrementally
python "${SKILL_DIR}/scripts/sync_boss_resumes.py" sync-all

# Sync all online jobs with command echoing; --verbose is a global option and must be placed before the subcommand
python "${SKILL_DIR}/scripts/sync_boss_resumes.py" --verbose sync-all

# Sync one job by numeric jobId or encrypted jobId
python "${SKILL_DIR}/scripts/sync_boss_resumes.py" sync-job --job-id 

# Refresh job index only
python "${SKILL_DIR}/scripts/sync_boss_resumes.py" refresh-jobs

# Dry run without downloading resumes
python "${SKILL_DIR}/scripts/sync_boss_resumes.py" sync-all --dry-run
```

Use the Python interpreter that has `boss_agent_cli` importable, otherwise the `friend_detail` fallback will be disabled. The script prints a warning to stderr (with `--verbose`) when this happens.

If `boss` is not on PATH, override with `--boss-bin ` or set `BOSS_BIN=` in the environment.

### ⚠️ Known limitation: `applications` returns 0 for recommended/chat-based candidates

`boss hr applications` **only returns candidates who formally applied to the job.** It returns 0 for:
- Candidates the recruiter contacted via **推荐牛人** (recommended by BOSS algorithm)
- Candidates from **主动搜索打招呼**
- Any candidate where `friendSource != 0` in the friend list

**Detection:** Run `boss hr chat` — if it also returns 0 or only 1-3 entries, your candidates are likely from recommendations, not formal applications.

**Fix — CDP friend list → CLI resume download (proven approach):**

Instead of relying on `sync_boss_resumes.py` (which calls `applications`), use this two-phase approach:

**Phase 1: CDP browser captures the full friend list**
```python
from patchright.sync_api import sync_playwright
import json

captured = {}
def on_resp(resp):
    if 'getBossFriendListV2' in resp.url:
        try: captured['fl'] = resp.json()
        except: pass

with sync_playwright() as p:
    browser = p.chromium.connect_over_cdp('http://localhost:9222')
    pg = browser.contexts[0].pages[0]  # NEVER new_page()
    pg.on('response', on_resp)
    pg.goto('https://www.zhipin.com/web/chat/index', wait_until='networkidle', timeout=30000)
    time.sleep(5)

    friends = captured['fl']['zpData']['friendList']
    # Each friend has: name, uid, encryptUid, securityId, encryptJobId, jobName
    # uid = friendId, encryptUid = encryptGeekId (for hr resume)
```
See `references/resume-download-via-friend-list.md` for the complete working script.

**Phase 2: CLI downloads each resume individually**
```python
import subprocess
for f in friends:
    result = subprocess.run([
        'boss.exe', '--role', 'recruiter', '--platform', 'zhipin',
        '--cdp-url', 'http://localhost:9222',
        'hr', 'resume', f['encryptUid'],
        '--job-id', f['encryptJobId'],
        '--security-id', f['securityId']
    ], capture_output=True, timeout=45, env=BOSS_ENV)
    # Save raw_response.json + resume.json + resume.md
    # Apply 3-6s random delay between downloads
```

**Parameter mapping (friend list → CLI):**
| friendList field | CLI parameter | Purpose |
|:----------------|:--------------|:--------|
| `encryptUid` | `encryptGeekId` | `boss hr resume` first arg |
| `securityId` | `--security-id` | Resume download auth token |
| `encryptJobId` | `--job-id` | Required job context |
| `uid` | — | Unique ID for file naming |

> ⚠️ This approach requires the CLI to be **properly logged in** (not a false positive). Run the login verification from boss-agent-cli first.

---

## Troubleshooting

| Symptom | Likely cause | Fix |
|---------|--------------|-----|
| `unrecognized arguments: --verbose` | Global option placed after the subcommand | Put `--verbose` before `sync-all` or `sync-job` |
| `[WinError 2] 系统找不到指定的文件` / `FileNotFoundError: boss` | Subprocess cannot find `boss` on PATH | Pass `--boss-bin ` or set `BOSS_BIN`; on Windows use `%USERPROFILE%\bin\boss.cmd` |
| Not logged in despite browser login | Wrong auth data dir | Use `--data-dir ~/.boss-agent` (Windows: `%USERPROFILE%\.boss-agent`) |
| CDP connection refused | Chrome was not started with remote debugging | Relaunch Chrome with `--remote-debugging-port=9222` |
| All candidates are `pending_security_id` | `applications` output lacks `securityId` and internal fallback failed | Run the script with a Python that has `boss_agent_cli` importable, or pass `--verbose` to see the import error |
| `zhipin-recruiter` platform error | Wrong platform name | Use `--platform zhipin` |
| Applications pagination stopped at page 100 | Hard cap reached | Re-run on the specific job, or split by other filters; the script warns to stderr when the cap is hit |

## Output Expectations

Report the following after each sync:

- resume root directory
- jobs discovered
- jobs updated
- candidates discovered
- resumes downloaded
- skipped existing resumes
- candidates pending `securityId`
- failures with exact error messages

A successful sync envelope shape:

```json
{
  "ok": true,
  "resume_root": "",
  "mode": "sync-all",
  "totals": {
    "candidates_discovered": 0,
    "downloaded": 0,
    "skipped_existing": 0,
    "pending_security_id": 0,
    "failed": 0
  }
}
```

## Safety and Etiquette

- Do not send messages to candidates.
- Do not change job online/offline status.
- Do not delete previous resumes or indexes during sync.
- Preserve raw API responses for debugging.
- Treat BOSS data as private recruiting data.
- Do not include downloaded candidate resumes in a distributable skill package.

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [1xiaoyueryuer](https://github.com/1xiaoyueryuer)
- **Source:** [1xiaoyueryuer/boss-hr-agent-toolkit](https://github.com/1xiaoyueryuer/boss-hr-agent-toolkit)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** yes
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: flagged — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-1xiaoyueryuer-boss-hr-agent-toolkit-boss-resume-downloader
- Seller: https://agentstack.voostack.com/s/1xiaoyueryuer
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
