Gates Block, Never Warn: Putting an AI Agent to Work on My Job Search
Since August an AI agent has read job postings, analyzed them and composed my CVs. It is fast, and it can also invent a fact, forget a rule or attach the wrong file. This post is about the controls that made it safe to use: an approval bound to the exact text, checks that block instead of warning, one file per fact, and measuring the agent against my own decisions.
Related project: Job Search Agent System: Human-in-the-Loop Decision Support
This post is based on the Job Search Agent System repository. The system I use every day is private; the public repository holds its design, its decisions and reference implementations written from scratch with invented data. Figures are the repository's own, as of 13 October 2026. No employer, posting or person is identifiable.
Hundreds of small decisions
A job search is not one decision but hundreds of small ones a week: which posting deserves a careful read, which one to discard, what each CV should emphasize, what to answer in a form. Since August 2026 an AI agent has done most of that reading and writing with me. Between then and mid-October some 14,800 postings passed through its radar, it analyzed 822 of them in writing, and 77 applications went out.
Speed was never the problem. The problem is that an agent that writes fast can also write wrong, confidently: invent a fact that sounds plausible, forget a rule agreed two weeks earlier, or attach a CV composed for a different employer. In a job search each of those mistakes is public and permanent. So the interesting work was not making the agent capable; it was deciding what it is not allowed to do on its own.
An approval bound to the exact text
Nothing leaves without my approval, and the approval is not a checkbox. When I approve a CV or a letter, the system records a fingerprint of the exact text I read. If a single character changes afterwards, whether the agent "improves" a sentence or a template re-renders differently, the fingerprint no longer matches and the document is blocked until I read it again. None of the 77 documents sent went out without that approval of its full text.
The design point is that the approval belongs to the text, not to the task. "I approved the application to this role" is a much weaker statement than "I approved these exact words", and only the second one survives an agent that keeps editing.
Gates block, never warn
Every application passes twelve checks before it can be sent, and every one of them blocks. There are no warnings. A warning asks a tired person, at night, to weigh a message they have seen fifty times before; it gets dismissed exactly when it matters. A blocking check turns the same rule into something that cannot be skipped by accident: either the condition holds, or the document does not move.
Some checks are mechanical, like a file that must exist or a section within its length. Others encode lessons. A one-click form once attached the first file in my uploaded list instead of the tailored CV, and that job board does not allow replacing it. The control that came out of it is boring and effective: the file shown on the form's review screen is checked by name, and the order of operations is fixed. The CV is composed, approved and loaded before the form's questions are even opened.
One fact lives in one file
The most effective control against invented facts is structural. Every claim a CV can make lives in a small, verified fragment: a role, a result, a skill with its evidence. About eighty of them. A per-posting CV only selects and orders fragments; it never writes a new claim. If the agent wants to say something that is not in a fragment, the answer is not to let it, but to write and verify the fragment first.
The same idea covers claims that were removed on purpose: a figure later re-measured more conservatively, a detail that should not travel. Keeping them out used to depend on memory, and copying an old paragraph into a new fragment was enough to bring one back. Now a list of retired claims is searched in the text extracted from every generated PDF. A script does not forget.
Rules carry a date
My own criteria changed during the search: a category of roles I had ruled out for my home city became interesting again. The rule changed; the discards it had justified did not, including one whose posting was still open. Since then, owner rules are dated data, and a script lists every live discard that cites a superseded rule. Changing my mind reopens the decisions that depended on it, instead of leaving them silently wrong.
Measuring the agent against me
An agent that is never measured drifts toward whatever feels productive. This one is evaluated against my decisions, in both directions. Of the 33 postings it recommended, I applied to 24, dropped 8 and left 1 pending. Of the 789 it discarded at triage, I reopened 5. Read together, the two numbers say something useful: its discards rarely needed reversing, while its recommendations are more generous than my own judgment. That is the safer side to err on; a missed opportunity is invisible, a bad application is not.
One failure shaped the evaluation itself. An analysis once listed my distance from a junior posting, several times the experience asked for and a graduate degree, as a strength. Nobody called. A recruiter reads overqualification as "will leave soon". It now counts as a risk and lowers the seniority score.
What I would tell someone building one
- Bind approval to content, not to intent. If the text can change after you approve it, you approved nothing.
- Make the safe path the only path. Every rule that matters should block. Warnings are where rules go to be ignored.
- Measure the agent against the human, both ways. What it recommends and what it discards tell you different things, and you need both to trust it.
I designed the process, the rules and the controls and operate the system daily; much of the code was written by the agent under my direction and review. It is built on Claude Code (skills, hooks and memory). Architecture, decisions, the full list of lessons and the reference code are in the public repository. Este artículo también está en español.
Comments
Comments live on GitHub Discussions: sign in with GitHub in the box below to reply, or open the thread on GitHub.
No GitHub account? Leave a comment here
Comments are reviewed before they appear. Your email is optional and is never published.