ワンクリックで
apply
Apply to a single job (URL or pasted page) with fit review, or drain the pending queue when no argument is given.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Apply to a single job (URL or pasted page) with fit review, or drain the pending queue when no argument is given.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Search a job board and autonomously apply to matching jobs one at a time, until paused, exhausted, or the max-applications cap is hit.
Write a tailored one-page cover letter from a job description and the user's resume, humanized for natural tone.
Parse a resume's uploaded PDF into structured JSON (basics, experience, projects, skills, education) and save it to the editor.
Fetch the latest verification code or magic link from the connected mailbox for a given board domain. Called by apply / auto-apply for 2FA and account-creation flows.
Remove signs of AI-generated writing from text. Use when editing or reviewing text to make it sound more natural and human-written. Based on Wikipedia's comprehensive "Signs of AI writing" guide. Detects and fixes patterns including: inflated symbolism, promotional language, superficial -ing analyses, vague attributions, em dash overuse, rule of three, AI vocabulary words, negative parallelisms, and excessive conjunctive phrases.
Produce a tailored interview prep sheet (behavioral, technical, system design, company) from a job description and the user's resume.
| name | apply |
| description | Apply to a single job (URL or pasted page) with fit review, or drain the pending queue when no argument is given. |
| argument-hint | [job_url_or_pasted_job_page] (omit to drain the queue) |
Two modes, one shared apply loop:
/api/queue/pending → score → ranked table approval → apply all.User approves once up front. No per-job confirmation after that.
Follow ../../shared/setup.md to load profile, resume, credentials.
JOBPILOT_API="${JOBPILOT_API:-https://jobpilot.suxrobgm.net}"
Read autoApply for config (defaults applied per field):
| Setting | Default | Notes |
|---|---|---|
minMatchScore | 60 | Batch-mode threshold (0-100). Ignored in single-job mode. |
maxApplicationsPerCampaign | null (unlimited) | Sent as config.maxApplications when set; omit for unlimited batch. Single-job mode forces 1. |
defaultStartDate | "2 weeks notice" | Default start-date answer. |
For ATS portals (Greenhouse, Lever, Workday, etc.) the apply step lands on a domain that isn't in /api/job-boards; the job-worker handles login/registration there per ../../shared/auth.md.
campaign <campaign-id> → re-apply mode: set CAMPAIGN_ID=<campaign-id>, set config.maxApplications = null (unlimited - the user hand-selected these jobs), skip Phases 1-4, and run the Phase 5 loop over its current approved jobs. (The campaign viewer - or the rescan-skipped skill - promotes the chosen skipped/failed jobs to approved before injecting this.)If the argument is pasted content (HTML / text), extract description, Apply URL, company, title. If no Apply URL can be found, stop: "I need either a job URL or content with a visible Apply link."
URL input → delegate to the job-worker subagent with mode:"review" so the posting snapshot stays out of this conversation: { "mode":"review", "url":"<job-url>", "resumeId":"<primary-or-empty>" }. Use its returned matchScore/strongMatches/partialMatches/gaps/blockers/visaRisk/verdict to fill the review below; keep its digest as DIGEST for 1.4.
Pasted input → parse the fields yourself (the content is already in hand), build the digest (../../shared/digest-schema.md), and POST /api/score-fit for the score. Keep the digest in DIGEST=... for 1.4.
## Job Fit Review: [Title] at [Company]
**Match Score: X/100**
**Strong Matches:** [skill - evidence]
**Partial Matches:** [skill - what's adjacent]
**Gaps:** [skill - what's missing]
**Visa/Sponsorship Risk:** [if mentioned]
**Verdict:** [1-2 sentence recommendation]
Ask: "Want me to proceed with the application?" - yes/go continue, anything else stop.
URL_ENCODED=$(jq -rn --arg v "<job-url>" '$v|@uri')
TITLE_ENCODED=$(jq -rn --arg v "<title>" '$v|@uri')
COMPANY_ENCODED=$(jq -rn --arg v "<company>" '$v|@uri')
curl -fsS -H "authorization: Bearer $JOBPILOT_API_TOKEN" "$JOBPILOT_API/api/applied/check?url=$URL_ENCODED&title=$TITLE_ENCODED&company=$COMPANY_ENCODED"
If .applied === true, surface the match (title + company + appliedAt + .match.kind) and ask whether to proceed anyway. Stop on no.
CAMPAIGN_ID=$(date -u +%Y-%m-%dT%H-%M-%S_apply)
curl -fsS -H "authorization: Bearer $JOBPILOT_API_TOKEN" -X POST "$JOBPILOT_API/api/campaigns" \
-H 'content-type: application/json' \
-d "$(jq -n --arg campaignId "$CAMPAIGN_ID" --arg query "<title> at <company>" \
'{campaignId:$campaignId, query:$query, source:"apply", config:{maxApplications:1}}')"
JOB_KEY=$(date -u +%s)-single
curl -fsS -H "authorization: Bearer $JOBPILOT_API_TOKEN" -X POST "$JOBPILOT_API/api/campaigns/$CAMPAIGN_ID/jobs" \
-H 'content-type: application/json' \
-d "$(jq -n --arg key "$JOB_KEY" --arg title "<title>" --arg company "<company>" \
--arg location "<location>" --arg url "<job-url>" --arg board "<board>" \
--arg matchReason "<one-line verdict>" --argjson score <0-100> \
--arg digest "$DIGEST" --arg desc "<posting text>" \
'{key:$key, title:$title, company:$company, location:$location, url:$url, board:$board, matchScore:$score, matchReason:$matchReason, status:"approved", digest:$digest, description:$desc}')"
Keep $CAMPAIGN_ID and $JOB_KEY. Live view: $JOBPILOT_WEB/campaigns/<CAMPAIGN_ID>. Jump to Phase 5.
curl -fsS -H "authorization: Bearer $JOBPILOT_API_TOKEN" "$JOBPILOT_API/api/queue/pending"
data is [{ id, url, note, status }]. If empty, tell user to open $JOBPILOT_WEB/queue to add URLs and stop. Otherwise: "Found N URLs in the queue. Visiting each to gather details..."
CAMPAIGN_ID=$(date -u +%Y-%m-%dT%H-%M-%S_apply)
curl -fsS -H "authorization: Bearer $JOBPILOT_API_TOKEN" -X POST "$JOBPILOT_API/api/campaigns" \
-H 'content-type: application/json' \
-d "$(jq -n --arg campaignId "$CAMPAIGN_ID" \
'{campaignId:$campaignId, query:"apply queue", source:"apply", config:{minScore:6, maxApplications:10}}')"
For each queue URL:
URL_ENCODED=$(jq -rn --arg v "<job-url>" '$v|@uri')
curl -fsS -H "authorization: Bearer $JOBPILOT_API_TOKEN" "$JOBPILOT_API/api/applied/check?url=$URL_ENCODED"
If applied, mark the queue entry consumed (status:"skipped") and add a skipped Job with skipReason:"Already applied (<kind>)", then continue - don't spawn a worker.
job-worker)Delegate the visit + score to the job-worker subagent - it opens its own tab, reads the posting, fuzzy-dedupes by title+company, scores, applies eligibility (../../shared/eligibility.md), and saves the Job row itself (so the full posting/digest never enters this conversation). One worker at a time. Input JSON:
{ "mode": "score", "campaignId": "<CAMPAIGN_ID>", "jobKey": "<entry-id>", "url": "<job-url>",
"board": "<domain>", "minMatchScore": <minMatchScore>, "resumeId": "<RESUME_ID>" }
It returns { outcome:"scored", jobKey, title, company, location, matchScore, confidence, eligible, skipReason, matchReason }. Collect these summaries for the ranked table (Phase 4) - the worker has already written each Job as pending (eligible) or skipped (with skipReason).
Auto mode (confirmMode: "auto" AND every qualified job ≥ threshold): PATCH all to approved, go to Phase 5.
Batch mode (default): present ranked table.
## Batch Apply
Visited <total> jobs. <qualified> qualify (score >= minMatchScore/100).
| # | Score | Title | Company | Location | Board |
|---|--------|-------|---------|----------|-------|
**Commands:** "go" | "go 1,3,5" | "remove 3" | "details 2" | "stop"
PATCH Job.status accordingly:
go → all qualified to approvedgo N,M → selected to approved; rest to skipped ("Not selected by user")remove N → that job to skipped ("Removed by user"); re-present tablestop → PATCH campaign status:"paused" and stopcurl -fsS -H "authorization: Bearer $JOBPILOT_API_TOKEN" -X PATCH "$JOBPILOT_API/api/campaigns/$CAMPAIGN_ID/jobs/<key>" \
-H 'content-type: application/json' -d '{"status":"approved"}'
For each approved job, score-descending:
curl -fsS -H "authorization: Bearer $JOBPILOT_API_TOKEN" -X PATCH "$JOBPILOT_API/api/campaigns/$CAMPAIGN_ID/jobs/<key>" \
-H 'content-type: application/json' -d '{"status":"applying"}'
job-worker)Delegate to the job-worker subagent and wait for its compact result - it navigates, authenticates, tailors, fills, and submits in its own tab/context (keeping the form snapshots out of this conversation). One worker at a time. Input JSON:
{ "mode": "apply", "campaignId": "<CAMPAIGN_ID>", "jobKey": "<key>", "url": "<job-url>",
"board": "<domain>", "resumeId": "<RESUME_ID>", "defaultStartDate": "<autoApply.defaultStartDate>",
"salaryExpectation": <remembered-or-null>, "preSubmitReview": <true when config.maxApplications === 1, else false> }
(digest omitted → the worker fetches it from the saved Job.)
Single-job pre-submit review: when preSubmitReview is true the worker fills everything, leaves the form open, and returns needs_user reason:"review" with a field summary. Present:
## Ready to Submit: [Title] at [Company]
| Name | Email | Phone | Resume | Salary | Start date | Cover letter | Custom Qs |
<total> fields across <P> page(s). Submit? (yes / no / edit <field>)
yes → re-delegate 5.2 with preSubmitReview:false (the worker submits the already-filled form). no → POST /result outcome:"skipped", skipReason:"User cancelled at pre-submit review". edit <field> → tell the worker what to change on re-delegation.
Map the worker's outcome to /result (the worker never writes it). The server atomically updates the Job, creates the Application (on applied), marks the queue, and recomputes the summary.
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
# applied
jq -n --arg t "$NOW" --argjson score <0-100> '{outcome:"applied", appliedAt:$t, matchScore:$score}'
# failed
jq -n --arg r "<failReason>" --arg notes "<retryNotes>" '{outcome:"failed", failReason:$r, retryNotes:$notes}'
# skipped (e.g. CAPTCHA, user cancelled, max-apps cap)
jq -n --arg r "<skipReason>" '{outcome:"skipped", skipReason:$r}'
needs_user: reason:"salary" → ask once, remember for the campaign, re-delegate 5.2 with salaryExpectation; reason:"2FA" or email verification → pause and ask; reason:"payment" → POST /result failed "Payment required". The worker closed its tabs; re-select tab 0, then continue.
If config.maxApplications is set and applied >= config.maxApplications, stop the loop. Leave remaining approved jobs as-is.
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
curl -fsS -H "authorization: Bearer $JOBPILOT_API_TOKEN" -X PATCH "$JOBPILOT_API/api/campaigns/$CAMPAIGN_ID" \
-H 'content-type: application/json' \
-d "$(jq -n --arg t "$NOW" '{status:"completed", completedAt:$t}')"
Print a summary table and link to $JOBPILOT_WEB/campaigns/<CAMPAIGN_ID>.
job-worker follows ../../shared/auth.md: register when no account exists (without asking), run forgot-password when the stored password is stale.needs_user reason:"payment", POST /result outcome:"failed", failReason:"Payment required".solve-captcha and returns skipped when unsolved; for needs_user reason:"2FA" or email verification, pause and ask (see ../../shared/auth.md)./result for terminal outcomes.skipped write carries a non-empty skipReason. No valid reason → not a skip.