suxrobgm/jobpilot/auto-apply
- community
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-applySKILL.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):
| 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 retryablefailedjob, 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.
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:
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:
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.
browser_navigatetosearchUrl(this is tab 1 - keep it open for the whole campaign).- Follow
../_shared/auth.md- logs in, and **registers a new account when none exists, without
asking**.
- Fill the search fields and submit.
- Take a
browser_snapshotnarrowed 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):
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-scorermode:"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):
With a usable score from the listing/tab-1 snapshot alone:
- Below `minMatchScore` after a fair read → create as
pending, POST/resultwith
outcome:"skipped", skipReason:"Below minimum match score ($SCORE < $MIN_SCORE)", and move on (no tab).
- Qualifies → add it as
applyingand apply (2.3). Write$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 withsalaryExpectationset.verification→ command the campaign topausedthrough/statuswith
{"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>):
status === "paused"→ POST/resultoutcome:"skipped", `skipReason:"Campaign paused by
user" for any in-flight applying` job, exit.
config.maxApplicationsset ANDsummary.applied >= config.maxApplications→ end. Unset
(default) = no cap; keep going.
- 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
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:
- Autonomous after launch. No per-job or batch confirmation; the UI launch is the approval.
- Board stays in tab 1. Each application runs in the
job-applier's own tab, which it closes
before returning.
- Respect pause. Re-read the campaign between jobs;
status === "paused"→ exit cleanly. - Missing resume file → command the campaign to
pausedthrough/statuswith
{"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
- SKILL.md in the repositoryCheckingplugin/skills/auto-apply/SKILL.md
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
[](https://verified-skill.com/skills/suxrobgm/jobpilot/auto-apply)