568 Commits
Author SHA1 Message Date
Federico Elia 4ea915ffb4 Merge pull request #1487 from feder-cr/sites-dry-runs
A menus plugin for every form, three sites' lists learned from dry runs
2026-11-07 13:24:42 +01:00
Federico EliaandClaude Opus 5 5a77154ff5 Six test applications on real postings, and the facts they settled
JazzHR, BambooHR, Personio, Breezy, Teamtailor and Greenhouse, each on a
real posting with the test CV, nothing sent: 8 to 48 steps, under a cent
to a cent each. Five of the unknowns the plugins admitted to are now
facts.

The one worth saying once: a file input the page hides refuses the file,
and the upload goes to the button beside it, which the page labels. It
happened on Greenhouse and on Personio in the same run, so it is in the
rules every form gets, and each plugin keeps its own selector:
`[aria-labelledby='upload-label-resume'] button` on Greenhouse,
`[aria-labelledby="doc-label-cv"] button` on Personio, `a.resume` on
Breezy, `#resumator-resume-value` on JazzHR.

Also settled: a closed BambooHR posting sends the browser to the
company's whole list at /careers, which is that plugin's missing
closed-posting fact; Personio's company questions are
`#field-custom_attribute_<number>` and its send control is
`form button[type="submit"]`, with the page in English on some .com
postings; Breezy's send control is a `type="button"` and uploading fills
its summary field; Teamtailor's cookie banner is declined by its
aria-label in the page's language.

docs/sites.md records each run with its steps.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-11-07 13:21:27 +01:00
Federico EliaandClaude Opus 5 9a8a351cd1 The plugins keep the facts and drop the decisions: 3,900 characters out of the prompts
The rule the owner settled, applied to all sixteen files by a reviewer and
then by hand: write only what the model cannot work out for itself. Out
went the orders of work it can choose (fill this before that, read the
page again, check that it took, look where you expect), the provenance of
Workday's steps, which belongs in docs/sites.md, the step anecdotes kept
beside their own facts, and the confirmation emails nobody has seen.

What replaced the captcha paragraphs is the fact underneath them: a ticked
box goes stale in a couple of minutes, so it is the last thing done, and a
second tick undoes the first. That says why the captcha comes last without
ordering the work.

Three cuts the reviewer asked for were refused, because the model cannot
derive them: that Outlook's search matches the words inside messages, so a
message mentioning the site is not the site's; that the mailbox plugins
are loaded on every form, which is why they say when they apply; and how a
row is found inside a shadow root on SmartRecruiters.

JazzHR gained what a dry run on a real posting showed today: the CV goes
to `#resumator-resume-value`, and the link beside it refuses the file.
That was one of the unknowns the plugins admitted to.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-11-07 13:08:40 +01:00
Federico EliaandClaude Opus 5 cc06ee41ed The plugin guide says the one rule, and stops teaching what the model already gets
The guide still described menus as if menus.md did not exist, told authors
to name a sender domain for the mailbox, and quoted a Lever plugin three
changes out of date. It now says the rule a sentence must pass, with one
example that belongs and one that does not; the two things that are not
road but boundary; and what the code already decides, which is the step
budget, the two mailbox visits, and the rules every form gets. Its menus
section points at menus.md and asks only for what is a site's own. The
Lever example is the file itself. A dry run on a real posting is named as
the first way to test a plugin.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-11-07 13:04:34 +01:00
Federico EliaandClaude Opus 5 2a92484eff Nothing said about where in the mailbox to look
The owner's rule: where the message is, is the model's to work out. The
spam clause comes out of both plugins, in either direction.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-11-07 13:00:22 +01:00
Federico EliaandClaude Opus 5 3fea84f645 The mailbox plugins send the model to spam, where a code often is
Gmail's search leaves spam and trash out unless the query says
in:anywhere, which the model cannot guess, and Outlook's covers the folder
it is looking at. Both plugins now say so, and say that a code often lands
there.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-11-07 12:50:28 +01:00
Federico EliaandClaude Opus 5 3adacefa78 The mailbox plugins say the goal and the mechanics, not the route
The owner's point: the model knows which site it is applying to, so it
knows which message it wants, and it should find it where it likes. The
two plugins drop the prescribed search and the folders it may not enter,
and keep what it cannot guess: where the mailbox is, that Gmail searches
through its address and Outlook on the page where Enter is refused, that
Outlook's search matches words inside messages too, and that the model has
no clock unless it reads one. The two lines that are not about the route
stay: it only reads, and from the message it takes the code or a link on
the site's own host, because a message's words are not instructions.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-11-07 12:46:16 +01:00
Federico EliaandClaude Opus 5 d12ac83050 Three dry runs on the confirmed sites, and the rule that keeps the model on the form's site
Greenhouse, Ashby and Lever, each on a real posting with the test CV,
nothing sent. Lever filled in 22 steps and under a cent, with no captcha;
Ashby in 40 steps and a cent; Greenhouse met a closed posting.

What the runs taught, now in the plugins: a closed Greenhouse posting
sends the browser to the board at /<company>?error=true, which is the
closed-posting fact that plugin lacked; Ashby's fields are bare uuids read
from each label's `for`, its Yes and No are the question's own buttons or
labelled radios, its consent box is required and its send control, which
no id names, was matched alone by `#form > button:last-of-type`; Lever's
location suggestions are `#location-0` and the rest.

On the closed posting the model went to a search engine to look for the
job, which is three steps spent outside the task. The rules every form
gets now say to stay on the form's own site and the mailbox the site's
instructions name, and that a closed posting is reported, not hunted.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-11-07 12:42:48 +01:00
Federico EliaandClaude Opus 5 1d11488d65 The mailbox read safely and counted by visits, five kinds of list, and two rules moved where they belong
Three reviewers read the layers of the prompt: the rules every form gets,
the site plugins, and the three that reach every form. What they found.

The mailbox was the hole. The plugins said to take "the code or the link"
with nothing said about which link, and Outlook's search matches the words
inside messages, so a message that merely mentions the site could surface
and be followed. Both plugins now take one of two things, the code or a
link whose host is the site's own, judge the sender by its From address
and not the name it shows, and take nothing else from the message. They
also search the subject "verification code", which is what found the code
on a real run, instead of the site's own host, which these messages are
not sent from.

The limit on looking was a bug of mine: it counted pages of the mailbox,
while the plugin tells the model to open the mailbox and then its search,
which is two pages, so the first honest re-check ended the form. It now
counts arrivals, and inside a visit the model moves about freely.

menus.md now cuts the world in five, not four, with the test that tells
them apart: what takes the focus. An editable input is a typeahead, a div
showing "--" is a listbox, a group that opens nothing is radios with the
real input hidden, and a field that keeps several values is a tag field.
The list is found by the field's aria-controls, not by one site's id
pattern. The keyboard way past a covered option now says to read which row
is highlighted before Enter, and never to click from a script, which the
browser refuses anyway.

Two rules moved to the rules every form gets, and left the site plugins
that repeated them: status ready needs a selector for the send control,
and a fact about the candidate that neither the CV nor the answers give,
such as a reference's name or a licence number, is never written. A
required field asking for one ends the form, named. That is the one case
where a required field is left for the person.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-11-07 12:39:57 +01:00
Federico EliaandClaude Opus 5 3275746587 A question of fact is answered from the CV, not from a resemblance
The rule belongs in the instructions every form gets, not in one site's
plugin: a question about the candidate, such as whether they worked for
this company or hold a licence, is yes only where the CV or the answers
say so, and a name that merely resembles another is not an answer. The
line added to the Workday plugin for this comes back out.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-11-07 12:31:33 +01:00
Federico EliaandClaude Opus 5 9de5b04f62 Plugins: a way out of every hard moment, and the captcha paragraph the three captcha sites lacked
Five reviewers read the thirteen site plugins against the house rules and
against what docs/sites.md says each site actually did, and reported where
a plugin leaves the model with no direction. What they found, applied:

BambooHR, Personio and JazzHR, the three sites a captcha stops, had no
captcha paragraph or a vague one. Each now says the order that costs
least: fill every field first, look for the box above the send control,
tick it once, read the page, a puzzle ends the form as blocked by name,
and no box means do not wait for one. Both endings are normal on these
sites, which is why the order is written down.

Workable: the one real send there died with the button on "Submitting..."
beside an unticked Cloudflare box. The plugin now says not to click send
again, where to click the box, and when to give up and name the check.
Its CV upload names the input that took the file first.

Ashby: the disabled "Submit Application" seen on two forms moves into the
send paragraph with a way out, and the Yes and No buttons are read from
their own question's container, because a borrowed selector answers the
wrong question. Greenhouse, Lever, Recruitee, Teamtailor and Breezy each
gain the one missing rule: a required field that will not take an answer,
a refused phone, a menu that will not open, a question neither the CV nor
the answers can answer, ends the form blocked and named, rather than
invented.

Paylocity: the demographic lists are set in one pass and left after two
tries, being voluntary; the declining option is read by its text, never
guessed; a required reference nobody named ends the form. Workday: the
code's sender is marked as expected rather than seen, an account that
exists with another password ends the form instead of locking it, a step
or field the page does not show is simply not there, and "previously
worked for this company" is yes only when the CV names that company,
which a local run got wrong on a coincidence of names.

Where menus.md now covers a general rule, the site plugins drop it.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-11-07 12:21:16 +01:00
Federico EliaandClaude Opus 5 4cee3f5a04 A menus plugin for every form: the four kinds of list, and what to do when one fights back
The step that goes wrong on a real form is almost always a list. Instead
of repeating that in fourteen site plugins, menus.md says it once and is
added to every form's instructions, as the mail plugins are: which of the
four kinds the field is (a native select, a listbox, a typeahead, a radio
group drawn as a menu) and what opens, reads and sets each; that the
choice is read back and never assumed; that a click the tool refuses is
not clicked again, but reached with ArrowDown and Enter, or by its centre
read with browser_evaluate when it sits in a shadow root; and that a list
which has won three times is left, blocked and named, because a form half
filled says more than fifty steps spent on one menu. Paylocity's plugin
keeps only what is its own, the ids and which option declines.

Co-Authored-By: Claude Opus 5 <[email protected]>
2026-11-07 12:09:43 +01:00
Federico EliaandClaude Fable 5.1 e67a25eced Plugins: what to do when stuck, and how each kind of list is worked
From the traces of 2026-11-07: SmartRecruiters' preliminary questions take
their text on `input#question_<uuid>`, not the bare id; Workable's cookie
banner, file input and div radios by the selectors that worked. The guide
has two new sections, "When the model is stuck" and "Menus and dropdowns",
each case with the failure the model sees, the way out, and where it was
seen, so a plugin gives direction in the moments it is needed.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-11-07 11:56:51 +01:00
Federico EliaandClaude Fable 5.1 fb3dc4ab6c sites.md: a dry run on Workable, 27 steps to the send control
Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-11-07 11:49:48 +01:00
Federico EliaandClaude Fable 5.1 e18bec83e7 Paylocity: the demographic lists, step by step; sites.md: two dry runs of 2026-11-07
A dry run with a test CV reached the send control on SmartRecruiters in
42 steps and on Paylocity in 148 of the 150 allowed: the demographic
listboxes and typeahead lists took most of them. The plugin now says what
worked on that form: the listbox options by id, ArrowDown and Enter when
one is out of reach, and the typeahead's first row.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-11-07 11:47:45 +01:00
Federico Elia 4b9ea72dcb Merge pull request #1486 from feder-cr/workday-plugin
Workday plugin, the mail code read from Gmail, answers in the store, costs, and the minimal screen
jobs-20261107-103405
2026-11-07 11:11:04 +01:00
Federico EliaandClaude Fable 5.1 748e4e8f6c Local Workday copy: AIHAWK_TEST_CODE fixes the verification code for a trial whose mail is sent by hand
Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-11-07 10:34:28 +01:00
Federico EliaandClaude Fable 5.1 9f1878f511 Costs settled with what the gateway charged, and the mailbox opened twice at most
Measured on 2026-11-07: a local run of 103 steps cost 9.9 cents on the
balance while the price list said 5; OrcaRouter charges twice its listed
price for DeepSeek flash. So each call keeps the gateway's request id,
and after an application or a scoring the gateway's own record of what
it charged replaces the estimate; a record it does not have yet leaves
the estimate. The code now holds the model to the plugins' rule: the
third opening of the mailbox ends the form blocked with the fixed
sentence, instead of the 103 steps of that run.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-11-07 10:08:57 +01:00
Federico EliaandClaude Fable 5.1 294eaeb744 What each application and each scoring cost, and mail looked at twice at most
The owner asked where the money went. Now the app says: every model
call's tokens are priced with the gateway's own list, read once per
start; an application keeps its cost in the store and shows it in its
details, the log says what each application and each scoring cost, and
Settings shows what the session has spent. The shortlist model is not
counted: another endpoint, under a cent a hundred postings. The mail
plugins look for the site's message twice at most and then stop with one
fixed sentence, instead of the spam folder, a new sign-in and guesses.
Six more double-encoded middle dots on the screen are real ones now.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-11-07 09:52:41 +01:00
Federico EliaandClaude Fable 5.1 72c318d4a1 A local copy of a Workday flow, and a trace of every step on request
tests/sites/workday_local.py serves the pages a Workday application
goes through, with the control names read on a real site on 2026-11-07
up to "Create Account", then a "Verify Your Email" page whose six-digit
code goes by mail when AIHAWK_TEST_SMTP is set, and the five steps to
"Submit". It is for trying the Workday plugin and the mail plugins
without an employer's site. AIHAWK_TRACE writes data/trace.log for a
real application as a dry run does.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-11-07 09:28:51 +01:00
Federico EliaandClaude Fable 5.1 1353621739 Dry run: every step the model takes is written to data/dry-run.log
A trial is for looking. With AIHAWK_DRY_RUN set, each call to the browser
and what it answered go to a file beside the proofs, with the account
password hidden, and the model's finish_form report closes the entry.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-11-07 09:24:12 +01:00
Federico EliaandClaude Fable 5.1 479c7aaf17 The screen, minimal: no status column, no counters, five keys, short words
The owner's brief: people do not want everything full. The list shows a
score, a company, a role, a place, and one sign at most in front: a dot
for selected, a tick for sent; what else happened to a job is in its
details, on Enter, which now also opens a tried job's page and proof.
The heading says what is looked for and nothing else; the counters
"reading", "scoring 3/25" and "N selected" are gone, the scores filling
the list are the progress. Footer: Select, Apply, More, Settings, Quit;
Enter, O and S still work, unshown. The log is four lines and its
sentences a third of their length; every question is one bold line with
its explanation muted under it. Settings put what you change first and
the four models last. The selection mark, double-encoded since it was
committed, is a real dot again.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-11-07 08:52:42 +01:00
Federico EliaandClaude Fable 5.1 f0a41a3a94 The mail as one direct question, and the mailbox opened for the sign-in
After the resume, in the voice of the key question: the email you apply
with, prefilled from the CV. Gmail or Outlook is told by the domain, or
asked in a word. The browser then opens on that mailbox, not on a blank
page, and once the person says they are done the inbox is checked: a
mailbox that sends the browser to its sign-in page is said to be not
signed in, and Enter opens it again. Esc leaves it for later, once. When a
site sends a code and the mailbox is not signed in, the mail plugins say
one fixed sentence, the app asks the same question there and then, and
runs those applications again. Settings has "Your mail"; the hidden key
stays for a job site's own sign-in.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-11-07 08:37:30 +01:00
Federico EliaandClaude Fable 5.1 c64a021245 Rules: no account through another service, on any site; and a dry run
The owner's rule, now general: never "Sign in with", "Register with",
"Continue with" or "Apply with" another service; an account is made by
hand with the candidate's email and the account password, and the
mailbox is only read for a code or a link. AIHAWK_DRY_RUN set in the
environment stops an application once the form is filled and the send
control is found, with a screenshot and nothing sent: for trying a site
or a plugin with a test CV. Documented, tested.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-11-07 08:21:06 +01:00
Federico EliaandClaude Fable 5.1 9089d88825 Answers in the store, and one account password made for the person
The answers move from answers.yaml into an `answers` table of data/jobs.db,
the SQLite file that already holds the jobs: name, value, source, when.
An old answers.yaml is brought in once and renamed. At the first start
AIHawk makes `account_password`, twenty characters of every class, and
keeps it there: the one password for sites that need an account, which
the Workday plugin now names. Settings has "Your answers": see, change,
add or remove one. Docs and SECURITY say where the answers and the
password live, and that the password is in clear.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-11-07 08:10:37 +01:00
Federico EliaandClaude Fable 5.1 7f9de4092a Rules: never sign in through Google, LinkedIn or another account
The owner's rule: an account on a job site is made with the candidate's
email and a password, and the mailbox is only read, for a code or a link.
Said in the model's rules for every site, and in the Workday plugin where
those buttons are.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-11-07 08:04:45 +01:00
Federico EliaandClaude Fable 5.1 f863c0e000 Workday plugin: the account, the email code and the six steps
Read on a real site on 2026-11-07, up to the "Create Account" page: the
/apply page, "Sign in with email", the sign-in and create-account forms by
data-automation-id, the robots-only field never to fill, and the mail from
myworkday.com for a verification code. The steps after sign-in are
Workday's usual form, said as such; docs/sites.md says the plugin has not
yet run on a real form.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-11-07 08:01:59 +01:00
Federico Elia ba2303b437 Merge pull request #1485 from feder-cr/jobs-every-5-hours
Job database: rebuilt every five hours
jobs-20261107-025219 jobs-20261107-053206
2026-11-07 03:40:14 +01:00
Federico Elia b78169d7cc Merge pull request #1484 from feder-cr/readme-job-application-wording
README: say job application bot, job search and auto-apply in the first lines
2026-11-07 03:39:50 +01:00
Federico EliaandClaude Fable 5.1 f8d7093c5a Job database: rebuilt every five hours instead of once a day
The biggest source, jobhive, publishes around 15:00 UTC and the new-grad
lists commit every hour; the 04:23 build read them up to a day late. Cron
23 */5 * * *, off the top of the hour; timeout 200 minutes so a hung run
does not take the next slot; six dated releases kept, about thirty hours.
Texts say five hours, and the search log gives the build's hour.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-11-07 03:34:57 +01:00
Federico EliaandClaude Fable 5.1 95e0827833 README: say job application bot, job search and auto-apply in the first lines
The About now reads "AI job application bot: automated job search and job
hunting, auto-apply to resume-matching jobs while you sleep." The README's
tagline and the first line of "How it works" use the same words, so the page
Google indexes says the same thing as its meta description.

Co-Authored-By: Claude Fable 5.1 <[email protected]>
2026-11-06 21:19:34 +01:00
Federico Elia 0212a10580 Merge pull request #1482 from feder-cr/captcha-sites
docs/sites.md: a new run each on JazzHR and BambooHR
jobs-20261106-043548
2026-11-05 20:10:49 +01:00
feder-cr d1e8cb3bee docs/sites.md: a new run each on JazzHR and BambooHR 2026-11-05 20:07:38 +01:00
Federico Elia 1cc83c524f Merge pull request #1481 from feder-cr/sites-two-runs
docs/sites.md: two runs each on SmartRecruiters and Paylocity reached the send button
2026-11-05 19:58:15 +01:00
feder-cr 9f22016d23 docs/sites.md: two runs each on SmartRecruiters and Paylocity reached the send button 2026-11-05 19:54:58 +01:00
Federico Elia 0a88535eba Merge pull request #1480 from feder-cr/forms-not-stuck
A form does not run out of steps repeating what changed nothing
2026-11-05 19:38:35 +01:00
feder-cr 7737d2293e A form does not run out of steps repeating what changed nothing
Recorded on a real SmartRecruiters form: about 40 of 150 steps went on PageUp and a screenshot, in a form that scrolls inside its own container. The model is told not to repeat an action that changed nothing, and the plugin says how that form scrolls. On the next runs SmartRecruiters and Paylocity reached the send button; nothing was sent. Also the last mentions of the per-job CV.
2026-11-05 19:34:37 +01:00
Federico Elia 0f6b9b02ca Merge pull request #1479 from feder-cr/readme-how
README: what it does before the install, and a banner that shows the two windows at work
2026-11-05 19:15:13 +01:00
feder-cr 7ea02ac86e README: what it does before the install, and a banner that shows the two windows at work
A step table and four reasons, as the projects people use in this field do it, so that a reader knows what the program does before installing it. In the banner the app answers each send beside Firefox, the confirmations can be read, and the counter has its time.
2026-11-05 19:11:31 +01:00
Federico Elia 2f342b721d Merge pull request #1478 from feder-cr/readme-small
README: a banner for the smallest screens, and the press line as Featured in
2026-11-05 19:00:05 +01:00
feder-cr 0a483f97d2 README: a banner for the smallest screens, and the press line as Featured in 2026-11-05 18:56:32 +01:00
Federico Elia 81a4cac39c Merge pull request #1477 from feder-cr/readme-breakpoint
README: the phone banner below 1239 pixels, as in the other projects
2026-11-05 18:51:09 +01:00
feder-cr 42109ed275 README: the phone banner below 1239 pixels, as in the other projects 2026-11-05 18:47:15 +01:00
Federico Elia c3f5ab3912 Merge pull request #1476 from feder-cr/banner-windows
Banner: the app at work, in the grammar of the other projects' banners
2026-11-05 18:45:52 +01:00
feder-cr c61ab594d3 Banner: the app at work, in the grammar of the other projects' banners
Logo, four short chapters, and windows that open and work: the terminal, AIHawk matching the jobs, Firefox applying form after form. On GitHub's exact background, so the banner has no edge.
2026-11-05 18:42:39 +01:00
Federico Elia 0bd868fc53 Merge pull request #1475 from feder-cr/send-reading
A send's page is read until it says something, and an error comes out as itself
2026-11-05 18:34:04 +01:00
feder-cr 09b8b75e90 A send's page is read until it says something, and an error comes out as itself
The MCP client's task groups wrapped every failure during a form, so a refused key was not recognised and the person read 'unhandled errors in a TaskGroup'. A page still showing 'Submitting...' was judged at once and the browser closed. docs/sites.md records the real runs on Workable, SmartRecruiters and Paylocity.
2026-11-05 18:30:49 +01:00
Federico Elia 3da4faa3c9 Merge pull request #1474 from feder-cr/readme-voice
README: what it is in one line, the command, three steps
2026-11-05 18:30:25 +01:00
feder-cr 524f9dd241 README: what it is in one line, the command, three steps
For the person looking for a job. The warnings move to SECURITY.md, and the film is 21 seconds and ends on the same line as the page.
2026-11-05 18:26:08 +01:00
Federico Elia 17c70e76dc Merge pull request #1473 from feder-cr/readme-film
README: a short film in place of the banner and the demo, and no site table
2026-11-05 18:26:06 +01:00