ENGINEERING JOURNAL · SEPTEMBER 2026
Building the AI Job Search Automation Platform
Turning a manual job search into a production-style AI automation platform — deterministic safety gates, grounded generation, reviewer critique, and why a security review catching my own overbroad privilege design was the best thing that happened to it.
Actively job searching well takes real, repeated effort: finding relevant postings, evaluating fit honestly, producing a genuinely tailored application for each one, and tracking status across dozens of open threads. Doing that manually doesn't scale, and doing it with a fragile personal script just trades one set of problems for another — silent failures, lost work, and no real safety net around the one action that actually matters: submitting something on my behalf.
I wanted to bring real production-engineering discipline to that problem instead: checkpointing, provider fallback, least privilege, automated testing — the same standards I try to hold my infrastructure work to, applied to my own career.
What I built
The platform discovers postings, deduplicates them against persistent state, filters them through deterministic eligibility rules before any AI call is made, scores the survivors for fit with an LLM, and generates tailored application content from my own verified background — a pattern I call Grounded Application Document Generation. Generation is explicitly constrained to that verified information and passes through an independent AI reviewer pass before anything is finalized. It's a disciplined process-and-review safeguard, not a claim that fabrication is technically impossible, and not a deterministic fact-checker.
Once a document is drafted and validated, it runs through a chain of submission safety gates — CAPTCHA and MFA detection, a completeness check, per-platform rate limits — and only proceeds to automated browser submission if every one of them clears. The moment anything is uncertain, it stops and hands the fully-prepared item back to me instead of guessing. I call that Human Authority at Consequential Boundaries: the platform is not, and isn't presented as, fully autonomous.
The problem that taught me the most
One operation genuinely needed elevated privilege: encrypting an account-creation credential using the host's native secret-sealing mechanism, which the automation's own service account couldn't call directly. My first design considered a privilege-escalation rule granting that service account permission to run the encryption tool itself.
On review, I caught the problem before it shipped: the way that privilege mechanism matches commands doesn't restrict which target file or option follows the granted command. As drafted, the rule would have handed the service account a general-purpose "decrypt or encrypt anything on this host using this mechanism" capability — not "manage this one application's own credentials," which was the actual requirement.
I replaced it with a minimal, single-purpose, root-owned helper that takes no command-line arguments at all, re-validates every field itself regardless of what the caller already checked, and operates only inside one directory it alone controls. The privilege grant names only that exact helper — nothing broader.
I don't think the story worth telling is "I designed it right the first time." It's that a review caught a real mistake before it reached production, and I can explain exactly why the fix is narrower and better. That's the judgment a security-conscious engineering process is actually supposed to produce.
Reliability problems that had nothing to do with AI
Some of the hardest bugs were entirely mundane. Early automation shared one interactive coding-assistant session's usage quota and process lifecycle — and both failed for real, mid-run, more than once, taking hours of progress with them. Fixing that meant moving every stage to standalone, checkpointed processes with their own AI-provider fallback and proper OS-service-managed execution, not tied to whatever happened to start them.
A subtler one: runtime state files became silently unreadable to one system identity the moment a different identity next rewrote them, because a standard atomic-write pattern creates its temp file at a fixed, restrictive permission mode regardless of the process's own configured permissions. Invisible in single-user development, real the moment two identities were genuinely in play. The fix is now a single shared, tested primitive every writer in the system uses.
What's public now, and what keeps evolving
The platform itself is an operational private system I run on my own schedule; the sanitized public showcase — architecture, security design, engineering-story write-ups, a synthetic-data dashboard demo, and real (unrounded) test statistics — is now published. Publishing the showcase doesn't mean development stopped; it means the parts worth sharing publicly are documented and safe to share, while the underlying platform keeps evolving.
What I learned
The AI parts of this system — ranking, drafting, reviewing — are a small part of what actually makes it trustworthy. The larger share is ordinary production engineering: deterministic rules wherever a fixed rule can substitute for a judgment call, fail-closed behavior everywhere an external dependency can be unavailable, least privilege end to end, and being honest in the documentation about exactly what a safeguard does and doesn't guarantee. Being precise about that — rather than rounding a disciplined process up to a mechanical guarantee — is part of the engineering, not just the writing.
Explore the public showcase on GitHub
← Back to the engineering journal