Skip to content
Automation
Skill

/auto-apply

Search a job board and autonomously apply to matching jobs one at a time, until paused, exhausted, or the max-applications cap is hit.

From plugin
jobpilot
7331 skills2 agents2 MCP
Install
$ npx -y skills add suxrobGM/jobpilot --skill auto-apply --agent claude-code

How it fires

How this skill gets triggered: by you, by Claude, or both.

  • Fires itselfAuto-invocation. Claude auto-loads it when your prompt matches the work.Auto-invocation is when the right skill fires by itself at the right moment, driven by a FLOW.md router and a hook, instead of you invoking it by name. It is the difference between a skill being installed and a skill actually getting used.Read the full definition →
  • You can call itInvoke it directly when you want it.
  • Slash command/auto-apply

Context preview

The summary Claude sees to decide when to auto-load this skill.

Search a job board and autonomously apply to matching jobs one at a time, until paused, exhausted, or the max-applications cap is hit.

SKILL.md

auto-apply.SKILL.md
name: auto-apply
description: Search a job board and autonomously apply to matching jobs one at a time, until paused, exhausted, or the max-applications cap is hit.
argument-hint: "<query> --board <domain> [--min-score N] [--max-apps N] | resume | retry-failed <campaign-id>"

Auto-apply - Search + Apply On Demand

Keep the chosen board open in tab 1; for each result that qualifies, delegate the application to the `job-worker` subagent (it works in its own tab and returns a compact result), then move to the next job. **No batch pre-discovery and no per-job approval - launching the campaign is the confirmation.** Pause only for 2FA / payment. **A CAPTCHA is not a pause** - attempt the `solve-captcha` skill; if unsolved, skip the job (never pause) and the user finishes it later via the `apply` skill. Live view at `$JOBPILOT_WEB/campaigns/<campaign-id>`.

Setup

Follow `../_shared/setup.md`. Shared campaign mechanics (applied-check, result writes, worker input, rules) live in `../_shared/campaign-flow.md`. Read `autoApply` (defaults applied per field):

| Setting | Default | Notes | | ---------------------------- | ------------------ | ----------------------------------------------------------------------------------------- | | `minMatchScore` | 60 | Qualification threshold (0-100). Inline `--min-score` overrides. | | `maxApplicationsPerCampaign` | `null` (unlimited) | Stop after this many successful applies. Inline `--max-apps` overrides; omit → unlimited. | | `defaultStartDate` | `"2 weeks notice"` | Default start-date answer. |

Inline argument overrides take precedence. `--board <domain>` is **required** unless the argument is `resume` or `retry-failed <campaign-id>`.

Campaign Modes

  • `"resume"` → list incomplete campaigns (`GET /api/campaigns?status=in_progress`), ask which to resume, replay the apply loop on remaining `applying`/`approved`/`pending` jobs.
  • `"retry-failed <campaign-id>"` → fetch the campaign; for every retryable `failed` job, POST its `/retry` command with the current `retryNotes`, then replay the apply loop on those approved rows.
  • Otherwise → search query → Phase 0.

To recover wrongly-`skipped` jobs, use the dedicated `rescan-skipped` skill (it re-scores and promotes to `approved`; apply them afterward).

Phase 0: Existing Campaign Check + Create

curl -fsS -H "authorization: Bearer $JOBPILOT_API_TOKEN" "$JOBPILOT_API/api/campaigns?status=in_progress"
curl -fsS -H "authorization: Bearer $JOBPILOT_API_TOKEN" "$JOBPILOT_API/api/campaigns?status=paused"

Each response is paginated; inspect its `.items` array.

If any matches, ask **"Found an incomplete campaign from `<startedAt>` (status: `<status>`). Resume or start fresh?"** Resume → inject the `resume-campaign` skill with that `campaignId`.

Otherwise the web UI already created the campaign row when the user submitted `/campaigns/new` - confirm it exists and use that `campaignId`. Capture its selected base resume: `RESUME_ID=$(curl -fsS -H "authorization: Bearer $JOBPILOT_API_TOKEN" "$JOBPILOT_API/api/campaigns/$CAMPAIGN_ID" | jq -r '.config.resumeId // ""')` (empty → fall back to the primary downstream). If invoked manually (rare), create one:

# resumeId is REQUIRED for auto-apply - default to the profile's primary.
RESUME_ID=$(curl -fsS -H "authorization: Bearer $JOBPILOT_API_TOKEN" "$JOBPILOT_API/api/user" | jq -r '.user.primaryResumeId // ""')
# maxApplications is OPTIONAL - omit the field entirely for unlimited mode.
CAMPAIGN=$(curl -fsS -H "authorization: Bearer $JOBPILOT_API_TOKEN" -X POST "$JOBPILOT_API/api/campaigns" \
  -H 'content-type: application/json' \
  -d "$(jq -n --arg q "<query>" --arg board "<domain>" --arg rid "$RESUME_ID" \
    --argjson minScore <n> \
    '{query:$q, source:"auto_apply", config:{board:$board, resumeId:$rid, minScore:$minScore}}')")
CAMPAIGN_ID=$(echo "$CAMPAIGN" | jq -r '.campaignId')

Surface live view: `$JOBPILOT_WEB/campaigns/<CAMPAIGN_ID>`.

Phase 1: Open the Board (tab 1)

1.1 Parse Query

Extract title/role, keywords, location, preferences. If vague, ask before searching.

1.2 Search the Chosen Board

Resolve the board:

curl -fsS -H "authorization: Bearer $JOBPILOT_API_TOKEN" "$JOBPILOT_API/api/job-boards" | jq --arg d "<domain>" '.[] | select(.domain == $d)'

If no row matches, command the campaign to `failed` with `POST /api/campaigns/$CAMPAIGN_ID/status {"status":"failed"}` and stop.

1. `browser_navigate` to `searchUrl` (this is **tab 1** - keep it open for the whole campaign). 2. Follow `../_shared/auth.md` - logs in, and **registers a new account when none exists, without asking**. 3. Fill the search fields and submit. 4. Take a `browser_snapshot` narrowed to the results list (per `../_shared/browser-tips.md`) to read `{ title, company, location, url }` per row. This is one viewport - scroll/paginate per **Pagination & infinite scroll** in `../_shared/browser-tips.md` as the loop drains rows (see **Stop Conditions**); never treat the first batch as all jobs.

Phase 2: Apply Loop (on demand)

Walk the tab-1 results top to bottom; at the last loaded row, scroll/page for more (per **Pagination & infinite scroll** in `../_shared/browser-tips.md`) before concluding. For each result:

2.1 Pre-filter (no tab)

Dedupe in-board by normalized title+company, then run the applied-check (`../_shared/campaign-flow.md`). If `.applied`, record the default already-applied skip and move on - **don't open a tab.**

2.2 Score

If the listing row lacks enough detail, read it from the tab-1 snapshot (don't navigate away). Build the digest (`../_shared/digest-schema.md`), then score server-side:

FIT=$(curl -fsS -H "authorization: Bearer $JOBPILOT_API_TOKEN" -
Read more
Ships withjobpilot

An AI agent that applies to jobs for you, on the Claude or Codex subscription you already have.

Get the whole plugin

Other skills on jobpilot.