Skip to content

Phase 4: autopilot applies to clean matches on its own, within your limits - #29

Merged
coderback merged 2 commits into
mainfrom
feat/autopilot
Oct 17, 2026
Merged

coderback merged 2 commits into
mainfrom
feat/autopilot

Conversation

@coderback

Copy link
Copy Markdown
Owner

Phase 4: autopilot with guardrails

Autopilot works down the job feed, best match first, and applies on its own only when nothing on the form needs you.

What it does per job

  1. Only forms on Greenhouse, Lever, Ashby or Workable (never LinkedIn/Indeed; Workday-style account sites are left to you). Each job is tried once.
  2. Fit is scored in batches; under the threshold (default 75) or a seniority stretch is recorded as skipped.
  3. Writes the tailored CV and cover letter and fact-checks both (doc_check.check_facts, the letter against the company research too).
  4. Fills the form in an unattended browser (apply_with_browser(decide=...)) and sends only if:
    • every answer came from the answer bank or the profile (none drafted, none left blank, none flagged),
    • no required field is still empty,
    • neither document claims something the profile doesn't back,
    • fewer than the daily limit (default 3) went out in the last 24 hours.
  5. Sent forms keep two screenshots (filled form, page after sending) and go in the tracker as Applied. A click the page doesn't confirm is recorded as unconfirmed (not Applied, still counts toward the limit, never retried automatically).
  6. Anything held goes to the Needs you queue with its reasons; answering a held question saves it to the answer bank, and Try again reruns that job.

Practice mode is the default: forms are filled, nothing is sent, and the run shows what would have gone. Sending is switched on in the page, behind a confirmation. Scheduled runs (every 6 hours) are off until switched on; Run now is always there.

API

  • app/autopilot.py: settings, ATS check, hold_reasons / document_problems, the run, background start, scheduler (keep_running, started in the lifespan).
  • tracker: autopilot_settings and autopilot_runs tables (one row per user + job), stale running rows finished on restart.
  • browser_agent.apply_with_browser(..., decide=): unattended finish (_finish_unattended), no review loop.
  • generate_cover_letter returns its research so the letter's fact check can use it.
  • ensure_full_description moved from main to jobs_db (autopilot needs it too).
  • Endpoints: GET /autopilot, PUT /autopilot/settings, POST /autopilot/run, GET /autopilot/runs, POST /autopilot/runs/{id}/retry|dismiss, GET /autopilot/runs/{id}/screenshots/{form|confirm}.

Frontend

/autopilot page (settings, live progress, Needs you / Sent / Practice / Skipped tabs with reasons, screenshots, documents, questions panel, Try again / Apply myself / Dismiss) and a sidebar entry with a badge for held forms.

Tests

  • api/tests/test_autopilot.py (33): the rule, ATS hosts, settings validation, full runs with the model and browser faked (practice, live, daily limit, held, unconfirmed, skipped, once per job, retries, tracked jobs), endpoints and per-user isolation.
  • Real Chromium: unattended run submits only when decide says so.
  • Playwright smoke test for the page; shell mocks include the runs endpoint.

Full suite: 771 passed; browser 16 passed; e2e 14 passed.

Works down the feed best match first: Greenhouse/Lever/Ashby/Workable forms only,
each job once, fit at or above the threshold and not a seniority stretch. Writes
and fact-checks the tailored CV and cover letter, fills the form in an unattended
browser, and sends it only when every answer came from the answer bank or the
profile, no required field is empty, the documents raise no fact flags and the
24-hour limit isn't reached. Practice mode (the default) never sends. Held forms
go to a queue with their reasons; sent ones keep form and confirmation screenshots.
Scheduled runs every 6 hours when switched on; /autopilot endpoints for settings,
runs, retry, dismiss and screenshots.
… and history

Practice or sending mode (sending asks first), lowest fit, daily limit and the
6-hourly schedule; live run progress; Needs you / Sent / Practice / Skipped tabs
with reasons, screenshots, documents, the questions panel to answer held
questions, Try again, Apply myself and Dismiss. Sidebar entry with a badge for
held forms.
@coderback
coderback merged commit c80c537 into main Oct 17, 2026
4 checks passed
@coderback
coderback deleted the feat/autopilot branch October 17, 2026 08:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant