Commit Graph
476 Commits
Author SHA1 Message Date
feder-cr c843b75165 Send words: Candidatar and its forms; Confirm, Finish, Complete only as the label or before an application 2026-11-05 06:24:17 +01:00
feder-cr a2dc29b491 Data sources: what each source's own licence says, and the credit they ask for 2026-11-05 04:58:15 +01:00
feder-cr cc598fddd7 Merge branch 'aihawk-app' into data-sources 2026-11-05 04:58:14 +01:00
feder-cr 1c054dc6d3 Data sources: list all 24, their licences and how to remove one 2026-11-05 04:56:20 +01:00
feder-cr 3cfdd23581 A test helper as a function, as ruff asks 2026-11-05 04:56:05 +01:00
feder-cr bffe28e385 Merge branch 'code-for-adopters' into aihawk-app 2026-11-05 04:13:04 +01:00
feder-cr 4ccd937475 Fix what a cold review found in the engine, the config and the dependencies
The browser gets the environment without the model key: the one the settings name, and the default.
rich is declared, as tui.py imports it.
Dead code removed: Store.to_apply, the threshold setting, and tests of removed names.
A new resume replaces the plan and keeps the person's filters, such as exclude.
An unreadable description database is reported once per search, and the search goes on.
_places has no empty part, so a place without a city no longer reads ", Italy".
The apply protocol is named Browser, not Session.
Confirm, Finish and Complete are held back from any element, as sends do.
Judge comments say why, with no numbers a reader cannot check.
2026-11-05 02:39:27 +01:00
feder-cr 90e63afe8f Docs for adopters: data, cost, responsibility, updates
README says what leaves the computer and what it costs, who answers for what is sent, how to update and uninstall, and where the search is changed. It states that the mail plugins' read-only rule is an instruction to the model, not enforced in code.

CONTRIBUTING: CI runs on Ubuntu, Windows and macOS, Python 3.11 and 3.12; ruff check runs the default rules, so the 160 line length is not enforced.
docs/plugins.md: the example is lever.md as it is.
SECURITY.md: the mail plugins' read-only rule is an instruction, not a guarantee.
Phone numbers removed from docs/sites.md and the SmartRecruiters plugin; the plugin gives a placeholder.
LLDB engine credit reworded in NOTICE and profile.py comment; CHANGELOG says what the repository was.
2026-11-05 02:24:27 +01:00
feder-cr efa34bd88e Send check: read a click's selector the way the engine finds its element, shadow roots and >> chains included 2026-11-05 02:07:43 +01:00
feder-cr 744d710e34 SmartRecruiters: the plugin says how the country, phone, CV and menus work; sites row updated from five real runs 2026-11-05 01:51:02 +01:00
feder-cr f1e764854f Sites: what forms did on real sites, without calling them unfinished 2026-11-05 01:07:58 +01:00
feder-cr 5356361bbb Docs: each site's real status in docs/sites.md, linked from the README
The README site list is replaced by a one-line summary and a link to a
table of status per site, from the real forms trials and the index counts.
Ashby's after-sending section quotes the page a real send showed; the
SmartRecruiters plugin says what stops it today.
2026-11-05 01:07:18 +01:00
feder-cr fd80fa6181 Forms: a navigating call is read until its page has changed, and only the latest picture stays in the prompt
A select, click or key press that leaves the site returns before the new page has begun to load, so the address read
right after it could still be the form's and the form went on. The page is now read again, for a short while, until its
document has changed (its time origin) or its address has. A page that stays the same is the answer, not a fault.

Each screenshot the model is sent stayed in every later call. Now only the latest one stays, and an older one is a note
that it was taken. The model acts on the latest picture.
2026-11-05 00:49:21 +01:00
feder-cr 9a4858ab52 Forms: refused selectors say what to do, shadow-root clicks are checked where they land, and a form that cannot finish stops with its report
A click the check cannot read (Playwright >> chains, :has-text, a control inside a shadow root) is refused with the way
to click it instead: browser_click_at on its centre. The point check reads the innermost element inside open shadow
roots, as the mouse reaches it, so a send control there is refused. A selector that also matches inside a shadow root is
not read. Space and Enter read the focused element inside shadow roots too.

A call refused three times in a row stops the form, and a form that reaches the step limit stops too. Either way the
model is asked once, with only finish_form, what is filled and what did not stick. It never comes back ready, and
needs_input keeps its questions. The step limit is unchanged.

The system rules say a >> or text-syntax selector is refused and what to click instead, and the SmartRecruiters plugin
says the Easy Apply form is in a shadow root.
2026-11-05 00:38:23 +01:00
feder-cr afd7e0a688 Merge branch 'hard-controls' into aihawk-app 2026-11-05 00:08:22 +01:00
feder-cr cde65e964b Teamtailor plugin: how a custom menu opens and reads, and what a refused tag field means 2026-11-04 23:05:05 +01:00
Federico Elia eb54b9b4f7 First-run fixes, forms on real sites, and what contributors need 2026-11-04 23:01:27 +01:00
feder-cr 4c68f897a0 Merge branch 'first-run-fixes' into aihawk-app 2026-11-04 22:52:27 +01:00
feder-cr f7ef2564bb First run: a refused key, quitting, 80 columns, plain errors, BOM files, install and CI
A key that OrcaRouter refuses is forgotten when it came from the key file, and asked for again; a key from the
environment is named by its variable and not forgotten. Ctrl+C leaves at every prompt, and leaving while a prompt
is open no longer raises NoMatches from the heading. Log lines wrap to the whole width, and Quit stays on the
footer at 80 columns. Database and model failures say what happened in plain words, with the detail after them.
Files saved with a byte-order mark are read. The README gives the install commands checked in new venvs, the
index size from the manifest, and how to change the key. CI runs the unit job on Python 3.11 and 3.12 on Ubuntu,
Windows and macOS; gate still needs all of it. The classifiers name the three systems.
2026-11-04 22:52:08 +01:00
feder-cr 7e2da5ab31 Merge branch 'captcha-click' into aihawk-app 2026-11-04 22:38:30 +01:00
feder-cr d2f93b5850 Texts: the one sentence about AIHawk everywhere, the README for a one-minute read, and true statements about models, mail and the database 2026-11-04 22:24:51 +01:00
feder-cr dcec5023b5 Captcha: a box to tick is clicked once, a puzzle is blocked
The form model may click a captcha shown as a box to tick (Turnstile,
reCAPTCHA), usually at its coordinates, wait a few seconds, read the page
again and try once more if the box is still unticked. A puzzle or image
challenge, a login wall or a closed posting is still blocked. No solving
service and no script on a captcha.

Tests: a click on the captcha's frame passes the guard, a captcha frame
does not count as sending or as touching the form, and a captcha click
followed by a send is handled through fill_form.
2026-11-04 22:17:10 +01:00
feder-cr 9094020f7f Open-source basics: CONTRIBUTING, the plugin guide, SECURITY, issue and pull request templates, CHANGELOG 2026-11-04 22:15:46 +01:00
feder-cr d1c3e2d0e6 Forms: deepseek-v4.1-flash by default; Enter allowed in a tag field that asks for it
The default form model moves to deepseek/deepseek-v4.1-flash: about 3 minutes and 1.5 US cents a form on 11 real sites,
85 of 100 on the hard local forms, level with the best within noise, where glm-5.3-flash took twice as long at three
times the cost.

Enter is refused everywhere except a bare Enter in a text input or textarea whose own placeholder or aria-label asks
for it (Paylocity's skills, Teamtailor's tags). Control+Enter and other combinations stay refused.
2026-11-04 21:18:09 +01:00
Federico Elia 69be2d40b5 AIHawk: find the jobs that fit your CV and apply to them 2026-11-04 19:15:02 +01:00
feder-cr ce01c37a31 Docstrings and plugin text: the selection and one Enter is the yes, no auto-submit; plugin after-sending notes say only what to read 2026-11-04 19:10:53 +01:00
feder-cr cdf2129e86 Merge branch 'send-and-list' into aihawk-app
# Conflicts:
#	README.md
#	tests/test_apply.py
#	tests/test_jobs.py
2026-11-04 19:06:20 +01:00
feder-cr 9840ed6da4 Send the selected jobs on one yes, keep what each page said, and list what was sent
One question before a batch is sent (Enter sends, Escape cancels); no per-job confirmation and no --auto-submit.
A form's questions are asked after the others are sent, then the form is tried again.
After the click the verifying model gets the plugin's text as its rules and the page as untrusted text.
Each clicked job keeps its time, final address, verdict and evidence, page text and a screenshot under data/proofs.
Key s lists every job tried with its plain status; applied.csv is rewritten after each attempt, cells that start like a formula are made text.
2026-11-04 19:04:47 +01:00
feder-cr 193b5ed027 Merge branch 'small-description-files' into aihawk-app 2026-11-04 18:58:54 +01:00
feder-cr a5ac30fbba Descriptions read one query per file: 128 MB files and 2048-row groups, measured at 470 MB to 111 MB per search 2026-11-04 18:58:31 +01:00
feder-cr 2d036b1d2c Lint: what the full rule set finds, unused noqa and an explicit check 2026-11-04 18:57:09 +01:00
feder-cr 776bfee32b Merge branch 'script-rung' into aihawk-app 2026-11-04 18:53:27 +01:00
feder-cr e9a9c7746e AIHawk: offer browser_evaluate as the last rung, watched after each call
The model may run script again, by the owner's decision, knowing a script could send a form without the person's yes.
NEVER_OFFERED is gone. The system prompt says script comes only after selectors, coordinates and a screenshot have
failed, and never to send the application. browser_evaluate counts as acting, so a script that leaves the form's host
stops the form as unconfirmed. The docstrings and the README say what holds.
2026-11-04 18:53:17 +01:00
feder-cr 0c82d4317a plugins: how to tell a sent application was received, per ATS
Each of the 12 site plugins gets a last section: what follows a submit,
with the evidence level per site (real send, saved page, documentation or
nothing). No form was submitted for this.
2026-11-04 18:50:12 +01:00
feder-cr 7179db6da6 Judge with Jev in batches: up to 85 postings and 180k tokens a request, split on failure 2026-11-04 18:33:55 +01:00
feder-cr 4ea8594019 Merge branch 'jev-cloud' into aihawk-app 2026-11-04 18:25:40 +01:00
feder-cr 1a837c5c72 Judge with Jev through OrcaRouter only: drop the local download, the process and the fallback 2026-11-04 18:25:32 +01:00
feder-cr 6f66f1b767 Read the page again after a change before it can end a form
A read that fails after a change says nothing: the page can be loading or still being typed into. It is read again a few
times, and only a page that is read and is on another host stops the form as unconfirmed. Personio's posting goes
straight to its form with apply_path /apply, so its apply link is no longer clicked.
2026-11-04 18:21:10 +01:00
feder-cr 5c676d8151 Place words start after a separator, a dash or a number, not after a word
Keeps Dallas TX, Berlin Office, Milano Via Turati and Dallas-Fort Worth; refuses New London, New Berlin and New South Wales.
2026-11-04 18:05:27 +01:00
feder-cr e2efac4135 Fix the defects of a real end-to-end run
Place words match whole parts of the location, so Wales is not New South Wales.
A location answered no scores 1, out of the top.
Progress counts while descriptions and jevos read; jevos is said to download or start only when it does.
Looking for shows the first wordings of the plan's nodes, not their ids.
A failed jevos verdict is counted once per batch, not taken for no opinion.
A scan's log lines reach the screen from the loop, not from its thread.
A judged posting with no description is marked no text in its status.
2026-11-04 17:57:38 +01:00
feder-cr 1572ff93b4 Merge branch 'guard-acting-tools' into aihawk-app 2026-11-04 17:40:53 +01:00
feder-cr 64ebd4aa42 apply: stop a form that leaves for another site after the model's own act, and hold the model to its sites 2026-11-04 17:40:39 +01:00
feder-cr 7686bcafe1 Judge the shortlist with jevos: the funnel replaces the title screen
jevos weighs the next 100 postings by title with six closed questions; the best 25 by the title's fit and that evidence go to the judge model for a score, and the rest are kept as passed over. The title screen, its status and its tests are gone.

jevos is pinned to jevos-v5 and downloaded at first use, checked by SHA-256 before unpacking. Where it cannot run, the cloud model answers the same questions; where there is no key either, the title decides.
2026-11-04 17:36:19 +01:00
feder-cr 0da41b3b69 README: shorter page, limits left out 2026-11-04 17:23:40 +01:00
feder-cr 99e2a8a16a README: the published database, shorter page 2026-11-04 17:23:34 +01:00
feder-cr 750e65ea80 README: what the app does now, the sites, the plan, the defaults 2026-11-04 17:23:03 +01:00
feder-cr b3338a99e4 apply: close the ways a form could leave without the person's yes
A review found them, each confirmed on the code. Script is no longer offered to the model: requestSubmit?.() passed every
check, and no check can tell what a script will do. Space on a focused control, a new line outside a text area, and an
image input are held back like the rest, and a renamed argument no longer lets Enter through.

The control the model names is clicked only if it is one that sends. A click that answers with an error, or a result that
cannot be read, is unconfirmed and never tried again: a real Ashby form disabled its button and was recorded as failed
when it may have gone.
2026-11-04 17:19:43 +01:00
feder-cr f8de6b19eb aihawk: one browser profile to sign in to, and prompts to read a code from the mail
The browser opens on one profile kept in the person's folder, and the key l opens it for them to sign in to their mail and
any site. Gmail and Outlook are plugins with `when: always`: they join the instructions of every form without making a
site count as supported, and say how to fetch a code or a link, only reading. Their pages come from public documentation
and have not been tried on a real mailbox.

The check on what sends a form knew few languages: Gmail's Senden passed it. It knows the main ones now.
2026-11-04 17:11:04 +01:00
feder-cr da5517bd4f aihawk: matching from a weighted plan graph, more sites, and the browser as its server says
The search plan is a graph of nodes and weighted forms with conditional arcs, after the owner's harrier engine, kept in
aihawk.yaml so it can be tuned. Search scores titles in Python from it, by rarity among the postings of the place, and a
town's name no longer matches where the country column says otherwise.

Judging asks closed questions and computes the score from the answers. Plugins now describe how each site's pages are
built; SmartRecruiters, Teamtailor, JazzHR, BambooHR and Personio are new, from rendered pages.

The browser window is visible. The model gets the server's own instructions, its rungs of coordinates and screenshots,
and any tool it marks read-only; a click at a point goes through the same check as a click on a selector. The form rules
now send certifications and unstated facts back as questions, after a real test ticked them. A daily run tries the
newest invisible-playwright-mcp.
2026-11-04 16:53:34 +01:00
feder-cr c88169fbb7 aihawk: one command and a screen in the terminal: give it a resume, select jobs, apply
`aihawk resume.pdf` is all a person types. The model reads the resume and works out what to search and the contact
details it states; the list of jobs, best first, fills in on a terminal screen as they are judged; space selects, a
applies, and what a form asks that the files do not say is asked there and remembered. Nothing is sent without y.

Searching the published files over the network took two minutes each time, so the database now publishes a light index
that is downloaded once a day and searched locally. A description is read from the database only for a job being judged.
Filters match whole words, so java is not javascript and roma is not Romania.
2026-11-04 13:02:20 +01:00