suxrobgm/jobpilot/auto-apply

Trust tier 3
  • community
Source check pending

Checking that the SKILL.md file is still in the repository.

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

Install

npx vskill@latest install suxrobgm/jobpilot/auto-apply

SKILL.md

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-applier 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):

SettingDefaultNotes
minMatchScore60Qualification threshold (0-100). Inline --min-score overrides.
maxApplicationsPerCampaignnull (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: Resolve the Campaign

`--campaign <id>` passed (the web UI always passes it - it created the campaign when the user submitted /campaigns/new): use it as CAMPAIGN_ID and skip the checks below.

No `--campaign` (manual run): look for an unfinished campaign first.

bash
jobpilot-api GET /api/campaigns --query status=in_progress --query source=auto_apply
jobpilot-api GET /api/campaigns --query status=paused --query source=auto_apply

A match in .items → ask "Found an incomplete campaign from `<startedAt>` (status: `<status>`). Resume or start fresh?" Resume → run the resume-campaign skill with that campaignId. Otherwise create one; resumeId defaults to user.primaryResumeId, and leave maxApplications out for unlimited:

bash
jobpilot-api POST /api/campaigns --data '{"query":"<query>","source":"auto_apply","config":{"board":"<domain>","resumeId":"<RESUME_ID>","minScore":<n>}}'

Read .campaignId as CAMPAIGN_ID.

Either way, read the campaign's config.resumeId as RESUME_ID (GET /api/campaigns/$CAMPAIGN_ID; absent → the primary) and surface the 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:

bash
jobpilot-api GET /api/job-boards

Pick the row whose .domain equals <domain>. If none 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**.

  1. Fill the search fields and submit.
  2. 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 brief (../_shared/job-brief.md), then score server-side. Write $JOBPILOT_TEMP/fit.json as {"brief": <brief object>, "minScore": <MIN_SCORE>, "resumeId": "<RESUME_ID>"} (drop resumeId when there is none):

bash
jobpilot-api POST /api/score-fit --data @"$JOBPILOT_TEMP/fit.json"

Read .score as SCORE and .verdict as FIT_VERDICT, then branch (eligibility per ../_shared/eligibility.md - a thin/generic row is not a skip):

  • Confident - FIT_VERDICT == "trust" → use the score directly.
  • Uncertain - FIT_VERDICT == "deliberate" → rescore yourself from

strongMatches/partialMatches/gaps.

  • Needs the full posting → delegate the row to job-scorer mode:"score"

({campaignId:$CAMPAIGN_ID, jobKey:<key>, url, resumeId:$RESUME_ID, minMatchScore:$MIN_SCORE}) instead of opening the posting in this conversation. The worker creates every row non-terminal and sends ineligible outcomes to /result; eligible rows remain pending. PATCH an eligible row to applying, then go straight to apply (2.3):

bash
jobpilot-api PATCH /api/campaigns/$CAMPAIGN_ID/jobs/<key> --data '{"status":"applying"}'

With a usable score from the listing/tab-1 snapshot alone:

  • Below `minMatchScore` after a fair read → create as pending, POST /result with

outcome:"skipped", skipReason:"Below minimum match score ($SCORE < $MIN_SCORE)", and move on (no tab).

  • Qualifies → add it as applying and apply (2.3). Write $JOBPILOT_TEMP/job.json:
json
{
"key": "<stable-id>",
"title": "<title>",
"company": "<company>",
"location": "<location>",
"url": "<url>",
"board": "<board>",
"matchScore": <0-100>,
"matchReason": "<one line>",
"status": "applying",
"brief": "<brief, stringified>",
"description": "<posting text, when read>"
}
bash
jobpilot-api POST /api/campaigns/$CAMPAIGN_ID/jobs --data @"$JOBPILOT_TEMP/job.json"
2.3 Apply (delegate to job-applier)

Hand the job to the job-applier subagent and wait for its compact result. It opens its own tab and runs auth, CAPTCHA, tailoring, form-fill, and submit in isolated context, so the form/posting snapshots never enter this conversation. One worker at a time - the browser is shared; never delegate the next job until this one returns.

Delegate with the job-applier input from ../_shared/campaign-flow.md, passing the brief built in 2.2 and preSubmitReview: false. It returns one of applied / failed / skipped / needs_user - handle in 2.4.

2.4 Record + Continue

The worker already closed its apply tab(s); re-select tab 0. Map its outcome to a terminal /result write and route needs_user per ../_shared/campaign-flow.md, with these campaign-loop specifics:

  • salary → re-delegate 2.3 with salaryExpectation set.
  • verification → command the campaign to paused through /status with

{"status":"paused","actor":"agent","reason":"<what's needed, e.g. LinkedIn 2FA>"}, tell the user what's needed, and exit the loop (the worker left its tab open).

  • payment → record the failure and continue with the next result.

Pace 3-5s before the next result.

2.5 Stop Conditions

The loop ends only on one of these. Before picking the next result, refetch the campaign (GET /api/campaigns/<CAMPAIGN_ID>):

  1. status === "paused" → POST /result outcome:"skipped", `skipReason:"Campaign paused by

user" for any in-flight applying` job, exit.

  1. config.maxApplications set AND summary.applied >= config.maxApplications → end. Unset

(default) = no cap; keep going.

  1. Board exhausted - per Pagination & infinite scroll in ../_shared/browser-tips.md (2

consecutive scrolls with no new rows). First batch done ≠ exhausted. With maxApplications unset, paginate until genuinely dry.

Phase 3: Summary

bash
jobpilot-api POST /api/campaigns/$CAMPAIGN_ID/status --data '{"status":"completed"}'

Print a summary table, link to $JOBPILOT_WEB/campaigns/<CAMPAIGN_ID>, suggest retry-failed <CAMPAIGN_ID>, the rescan-skipped skill on <CAMPAIGN_ID> to recover dropped jobs, or a new search.

Rules

The shared campaign rules (../_shared/campaign-flow.md) apply throughout. On top of them:

  1. Autonomous after launch. No per-job or batch confirmation; the UI launch is the approval.
  2. Board stays in tab 1. Each application runs in the job-applier's own tab, which it closes

before returning.

  1. Respect pause. Re-read the campaign between jobs; status === "paused" → exit cleanly.
  2. Missing resume file → command the campaign to paused through /status with

{"status":"paused","actor":"agent","reason":"Resume file missing"}, ask the user to re-upload.

Security

  • Security scanPassed, 90 of 100Pattern checks on the skill's files.
  • Model reviewPassed

Quality evaluation

  • Task evaluationNot runNo evaluation yet. Run one in Skill Studio.

Source

Popularity

7-day trend score
0

Not refreshed yet.

Works with

Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.

  • Claude Code
  • Cursor
  • GitHub Copilot
  • Windsurf
  • Codex
  • Gemini CLI
  • Cline
  • Amp
  • Roo Code
  • Goose
  • Continue
  • Kilo Code
  • Junie
  • Trae
  • OpenHands
  • Qwen Code
  • AI Agent
  • Tabnine Chat
  • Sourcegraph Cody
  • Amazon Q
  • Firebase Genkit
  • Sweep
  • Devin
  • Phind
  • Mentat
  • Claude Desktop
  • Aider
  • GPT Pilot
  • Plandex
  • bolt.new
  • v0
  • Replit Agent
  • Anse
  • TypingMind
  • BetterChatGPT
  • LibreChat
  • Warp AI
  • Pieces
  • Fig AI
Embed badge
vskill VERIFIED badge
[![vskill VERIFIED](https://verified-skill.com/api/v1/skills/suxrobgm/jobpilot/auto-apply/badge)](https://verified-skill.com/skills/suxrobgm/jobpilot/auto-apply)

Something wrong with this skill or its page? Tell us.